aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8.1/gcc/go/gofrontend
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8.1/gcc/go/gofrontend')
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/LICENSE27
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/PATENTS22
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/README53
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/ast-dump.cc469
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/ast-dump.h122
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/backend.h479
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/dataflow.cc278
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/dataflow.h91
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/export.cc491
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/export.h201
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/expressions.cc14467
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/expressions.h2268
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/go-dump.cc53
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/go-dump.h38
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/go-linemap.h131
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/go-optimize.cc53
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/go-optimize.h38
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/go.cc146
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/gogo-tree.cc2506
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/gogo.cc5572
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/gogo.h2939
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/import-archive.cc660
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/import.cc960
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/import.h359
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/lex.cc2419
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/lex.h502
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/operator.h66
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/parse.cc5676
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/parse.h335
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/runtime.cc402
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/runtime.def373
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/runtime.h51
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/statements.cc5918
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/statements.h1570
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/string-dump.h25
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/types.cc9819
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/types.h3085
-rw-r--r--gcc-4.8.1/gcc/go/gofrontend/unsafe.cc96
38 files changed, 0 insertions, 62760 deletions
diff --git a/gcc-4.8.1/gcc/go/gofrontend/LICENSE b/gcc-4.8.1/gcc/go/gofrontend/LICENSE
deleted file mode 100644
index 6a66aea5e..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/gcc-4.8.1/gcc/go/gofrontend/PATENTS b/gcc-4.8.1/gcc/go/gofrontend/PATENTS
deleted file mode 100644
index 733099041..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/PATENTS
+++ /dev/null
@@ -1,22 +0,0 @@
-Additional IP Rights Grant (Patents)
-
-"This implementation" means the copyrightable works distributed by
-Google as part of the Go project.
-
-Google hereby grants to You a perpetual, worldwide, non-exclusive,
-no-charge, royalty-free, irrevocable (except as stated in this section)
-patent license to make, have made, use, offer to sell, sell, import,
-transfer and otherwise run, modify and propagate the contents of this
-implementation of Go, where such license applies only to those patent
-claims, both currently owned or controlled by Google and acquired in
-the future, licensable by Google that are necessarily infringed by this
-implementation of Go. This grant does not include claims that would be
-infringed only as a consequence of further modification of this
-implementation. If you or your agent or exclusive licensee institute or
-order or agree to the institution of patent litigation against any
-entity (including a cross-claim or counterclaim in a lawsuit) alleging
-that this implementation of Go or any code incorporated within this
-implementation of Go constitutes direct or contributory patent
-infringement, or inducement of patent infringement, then any patent
-rights granted to you under this License for this implementation of Go
-shall terminate as of the date such litigation is filed.
diff --git a/gcc-4.8.1/gcc/go/gofrontend/README b/gcc-4.8.1/gcc/go/gofrontend/README
deleted file mode 100644
index 6d4d0b0a8..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/README
+++ /dev/null
@@ -1,53 +0,0 @@
-See ../README.
-
-The frontend is written in C++.
-
-The frontend lexes and parses the input into an IR specific to this
-frontend known as gogo. It then runs a series of passes over the
-code.
-
-Finally it converts gogo to gcc's GENERIC. A goal is to move the gcc
-support code into a gcc-interface subdirectory. The gcc code will be
-put under the GPL. The rest of the frontend will not include any gcc
-header files.
-
-Issues to be faced in this transition:
-
-* Representation of source locations.
- + Currently the frontend uses gcc's source_location codes, using the
- interface in libcpp/line-map.h.
-
-* Handling of error messages.
- + Currently the frontend uses gcc's error_at and warning_at
- functions.
- + Currently the frontend uses gcc's diagnostic formatter, using
- features such as %<%> for appropriate quoting.
- + Localization may be an issue.
-
-This compiler works, but the code is a work in progress. Notably, the
-support for garbage collection is ineffective and needs a complete
-rethinking. The frontend pays little attention to its memory usage
-and rarely frees any memory. The code could use a general cleanup
-which we have not had time to do.
-
-Contributing
-=============
-
-To contribute patches to the files in this directory, please see
-http://golang.org/doc/gccgo_contribute.html .
-
-The master copy of these files is hosted at
-http://code.google.com/p/gofrontend . Changes to these files require
-signing a Google contributor license agreement. If you are the
-copyright holder, you will need to agree to the individual contributor
-license agreement at
-http://code.google.com/legal/individual-cla-v1.0.html. This agreement
-can be completed online.
-
-If your organization is the copyright holder, the organization will
-need to agree to the corporate contributor license agreement at
-http://code.google.com/legal/corporate-cla-v1.0.html.
-
-If the copyright holder for your code has already completed the
-agreement in connection with another Google open source project, it
-does not need to be completed again.
diff --git a/gcc-4.8.1/gcc/go/gofrontend/ast-dump.cc b/gcc-4.8.1/gcc/go/gofrontend/ast-dump.cc
deleted file mode 100644
index 850e31a81..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/ast-dump.cc
+++ /dev/null
@@ -1,469 +0,0 @@
-// ast-dump.cc -- AST debug dump. -*- C++ -*-
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include <iostream>
-#include <fstream>
-
-#include "gogo.h"
-#include "expressions.h"
-#include "statements.h"
-#include "types.h"
-#include "ast-dump.h"
-#include "go-c.h"
-#include "go-dump.h"
-
-// The -fgo-dump-ast flag to activate AST dumps.
-
-Go_dump ast_dump_flag("ast");
-
-// This class is used to traverse the tree to look for blocks and
-// function headers.
-
-class Ast_dump_traverse_blocks_and_functions : public Traverse
-{
- public:
- Ast_dump_traverse_blocks_and_functions(Ast_dump_context* ast_dump_context)
- : Traverse(traverse_blocks | traverse_functions),
- ast_dump_context_(ast_dump_context)
- { }
-
- protected:
- int
- block(Block*);
-
- int
- function(Named_object*);
-
- private:
- Ast_dump_context* ast_dump_context_;
-};
-
-// This class is used to traverse the tree to look for statements.
-
-class Ast_dump_traverse_statements : public Traverse
-{
- public:
- Ast_dump_traverse_statements(Ast_dump_context* ast_dump_context)
- : Traverse(traverse_statements),
- ast_dump_context_(ast_dump_context)
- { }
-
- protected:
- int
- statement(Block*, size_t* pindex, Statement*);
-
- private:
- Ast_dump_context* ast_dump_context_;
-};
-
-// For each block we enclose it in brackets.
-
-int Ast_dump_traverse_blocks_and_functions::block(Block * block)
-{
- this->ast_dump_context_->print_indent();
- this->ast_dump_context_->ostream() << "{" << std::endl;
- this->ast_dump_context_->indent();
-
- // Dump statememts.
- Ast_dump_traverse_statements adts(this->ast_dump_context_);
- block->traverse(&adts);
-
- this->ast_dump_context_->unindent();
- this->ast_dump_context_->print_indent();
- this->ast_dump_context_->ostream() << "}" << std::endl;
-
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// Dump each traversed statement.
-
-int
-Ast_dump_traverse_statements::statement(Block* block, size_t* pindex,
- Statement* statement)
-{
- statement->dump_statement(this->ast_dump_context_);
-
- if (statement->is_block_statement())
- {
- Ast_dump_traverse_blocks_and_functions adtbf(this->ast_dump_context_);
- statement->traverse(block, pindex, &adtbf);
- }
-
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// Dump the function header.
-
-int
-Ast_dump_traverse_blocks_and_functions::function(Named_object* no)
-{
- this->ast_dump_context_->ostream() << no->name();
-
- go_assert(no->is_function());
- Function* func = no->func_value();
-
- this->ast_dump_context_->ostream() << "(";
- this->ast_dump_context_->dump_typed_identifier_list(
- func->type()->parameters());
-
- this->ast_dump_context_->ostream() << ")";
-
- Function::Results* res = func->result_variables();
- if (res != NULL && !res->empty())
- {
- this->ast_dump_context_->ostream() << " (";
-
- for (Function::Results::const_iterator it = res->begin();
- it != res->end();
- it++)
- {
- if (it != res->begin())
- this->ast_dump_context_->ostream() << ",";
- Named_object* no = (*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_->dump_type(resvar->type());
-
- }
- this->ast_dump_context_->ostream() << ")";
- }
-
- this->ast_dump_context_->ostream() << " : ";
- this->ast_dump_context_->dump_type(func->type());
- this->ast_dump_context_->ostream() << std::endl;
-
- return TRAVERSE_CONTINUE;
-}
-
-// Class Ast_dump_context.
-
-Ast_dump_context::Ast_dump_context(std::ostream* out /* = NULL */,
- bool dump_subblocks /* = true */)
- : indent_(0), dump_subblocks_(dump_subblocks), ostream_(out), gogo_(NULL)
-{
-}
-
-// Dump files will be named %basename%.dump.ast
-
-const char* kAstDumpFileExtension = ".dump.ast";
-
-// Dump the internal representation.
-
-void
-Ast_dump_context::dump(Gogo* gogo, const char* basename)
-{
- std::ofstream* out = new std::ofstream();
- std::string dumpname(basename);
- dumpname += ".dump.ast";
- out->open(dumpname.c_str());
-
- if (out->fail())
- {
- error("cannot open %s:%m, -fgo-dump-ast ignored", dumpname.c_str());
- return;
- }
-
- this->gogo_ = gogo;
- this->ostream_ = out;
-
- Ast_dump_traverse_blocks_and_functions adtbf(this);
- gogo->traverse(&adtbf);
-
- out->close();
-}
-
-// Dump a textual representation of a type to the
-// the dump file.
-
-void
-Ast_dump_context::dump_type(const Type* t)
-{
- if (t == NULL)
- this->ostream() << "(nil type)";
- else
- // FIXME: write a type pretty printer instead of
- // using mangled names.
- if (this->gogo_ != NULL)
- this->ostream() << "(" << t->mangled_name(this->gogo_) << ")";
-}
-
-// Dump a textual representation of a block to the
-// the dump file.
-
-void
-Ast_dump_context::dump_block(Block* b)
-{
- Ast_dump_traverse_blocks_and_functions adtbf(this);
- b->traverse(&adtbf);
-}
-
-// Dump a textual representation of an expression to the
-// the dump file.
-
-void
-Ast_dump_context::dump_expression(const Expression* e)
-{
- e->dump_expression(this);
-}
-
-// Dump a textual representation of an expression list to the
-// the dump file.
-
-void
-Ast_dump_context::dump_expression_list(const Expression_list* el,
- bool as_pairs /* = false */)
-{
- if (el == NULL)
- return;
-
- for (std::vector<Expression*>::const_iterator it = el->begin();
- it != el->end();
- it++)
- {
- if ( it != el->begin())
- this->ostream() << ",";
- if (*it != NULL)
- (*it)->dump_expression(this);
- else
- this->ostream() << "NULL";
- if (as_pairs)
- {
- this->ostream() << ":";
- ++it;
- (*it)->dump_expression(this);
- }
- }
-}
-
-// Dump a textual representation of a typed identifier to the
-// the dump file.
-
-void
-Ast_dump_context::dump_typed_identifier(const Typed_identifier* ti)
-{
- this->ostream() << ti->name() << " ";
- this->dump_type(ti->type());
-}
-
-// Dump a textual representation of a typed identifier list to the
-// the dump file.
-
-void
-Ast_dump_context::dump_typed_identifier_list(
- const Typed_identifier_list* ti_list)
-{
- if (ti_list == NULL)
- return;
-
- for (Typed_identifier_list::const_iterator it = ti_list->begin();
- it != ti_list->end();
- it++)
- {
- if (it != ti_list->begin())
- this->ostream() << ",";
- this->dump_typed_identifier(&(*it));
- }
-}
-
-// Dump a textual representation of a temporary variable to the
-// the dump file.
-
-void
-Ast_dump_context::dump_temp_variable_name(const Statement* s)
-{
- go_assert(s->classification() == Statement::STATEMENT_TEMPORARY);
- // Use the statement address as part of the name for the temporary variable.
- this->ostream() << "tmp." << (uintptr_t) s;
-}
-
-// Dump a textual representation of a label to the
-// the dump file.
-
-void
-Ast_dump_context::dump_label_name(const Unnamed_label* l)
-{
- // Use the unnamed label address as part of the name for the temporary
- // variable.
- this->ostream() << "label." << (uintptr_t) l;
-}
-
-// Produce a textual representation of an operator symbol.
-
-static const char*
-op_string(Operator op)
-{
-// FIXME: This should be in line with symbols that are parsed,
-// exported and/or imported.
- switch (op)
- {
- case OPERATOR_PLUS:
- return "+";
- case OPERATOR_MINUS:
- return "-";
- case OPERATOR_NOT:
- return "!";
- case OPERATOR_XOR:
- return "^";
- case OPERATOR_OR:
- return "|";
- case OPERATOR_AND:
- return "&";
- case OPERATOR_MULT:
- return "*";
- case OPERATOR_OROR:
- return "||";
- case OPERATOR_ANDAND:
- return "&&";
- case OPERATOR_EQEQ:
- return "==";
- case OPERATOR_NOTEQ:
- return "!=";
- case OPERATOR_LT:
- return "<";
- case OPERATOR_LE:
- return "<=";
- case OPERATOR_GT:
- return ">";
- case OPERATOR_GE:
- return ">=";
- case OPERATOR_DIV:
- return "/";
- case OPERATOR_MOD:
- return "%";
- case OPERATOR_LSHIFT:
- return "<<";
- case OPERATOR_RSHIFT:
- return "//";
- case OPERATOR_BITCLEAR:
- return "&^";
- case OPERATOR_CHANOP:
- return "<-";
- case OPERATOR_PLUSEQ:
- return "+=";
- case OPERATOR_MINUSEQ:
- return "-=";
- case OPERATOR_OREQ:
- return "|=";
- case OPERATOR_XOREQ:
- return "^=";
- case OPERATOR_MULTEQ:
- return "*=";
- case OPERATOR_DIVEQ:
- return "/=";
- case OPERATOR_MODEQ:
- return "%=";
- case OPERATOR_LSHIFTEQ:
- return "<<=";
- case OPERATOR_RSHIFTEQ:
- return ">>=";
- case OPERATOR_ANDEQ:
- return "&=";
- case OPERATOR_BITCLEAREQ:
- return "&^=";
- case OPERATOR_PLUSPLUS:
- return "++";
- case OPERATOR_MINUSMINUS:
- return "--";
- case OPERATOR_COLON:
- return ":";
- case OPERATOR_COLONEQ:
- return ":=";
- case OPERATOR_SEMICOLON:
- return ";";
- case OPERATOR_DOT:
- return ".";
- case OPERATOR_ELLIPSIS:
- return "...";
- case OPERATOR_COMMA:
- return ",";
- case OPERATOR_LPAREN:
- return "(";
- case OPERATOR_RPAREN:
- return ")";
- case OPERATOR_LCURLY:
- return "{";
- case OPERATOR_RCURLY:
- return "}";
- case OPERATOR_LSQUARE:
- return "[";
- case OPERATOR_RSQUARE:
- return "]";
- default:
- go_unreachable();
- }
- return NULL;
-}
-
-// Dump a textual representation of an operator to the
-// the dump file.
-
-void
-Ast_dump_context::dump_operator(Operator op)
-{
- this->ostream() << op_string(op);
-}
-
-// Size of a single indent.
-
-const int Ast_dump_context::offset_ = 2;
-
-// Print indenting spaces to dump file.
-
-void
-Ast_dump_context::print_indent()
-{
- for (int i = 0; i < this->indent_ * this->offset_; i++)
- this->ostream() << " ";
-}
-
-// Dump a textual representation of the ast to the
-// the dump file.
-
-void Gogo::dump_ast(const char* basename)
-{
- if (::ast_dump_flag.is_enabled())
- {
- Ast_dump_context adc;
- adc.dump(this, basename);
- }
-}
-
-// Implementation of String_dump interface.
-
-void
-Ast_dump_context::write_c_string(const char* s)
-{
- this->ostream() << s;
-}
-
-void
-Ast_dump_context::write_string(const std::string& s)
-{
- this->ostream() << s;
-}
-
-// Dump statment to stream.
-
-void
-Ast_dump_context::dump_to_stream(const Statement* stm, std::ostream* out)
-{
- Ast_dump_context adc(out, false);
- stm->dump_statement(&adc);
-}
-
-// Dump expression to stream.
-
-void
-Ast_dump_context::dump_to_stream(const Expression* expr, std::ostream* out)
-{
- Ast_dump_context adc(out, false);
- expr->dump_expression(&adc);
-} \ No newline at end of file
diff --git a/gcc-4.8.1/gcc/go/gofrontend/ast-dump.h b/gcc-4.8.1/gcc/go/gofrontend/ast-dump.h
deleted file mode 100644
index 55c93693f..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/ast-dump.h
+++ /dev/null
@@ -1,122 +0,0 @@
-// ast-dump.h -- AST debug dump. -*- C++ -*-
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_AST_DUMP_H
-#define GO_AST_DUMP_H
-
-#include "string-dump.h"
-
-class Expression;
-class Expression_list;
-class Named_object;
-class Statement;
-class Gogo;
-
-// This class implements fgo-dump-ast. the
-// Abstract syntax tree dump of the Go program.
-
-class Ast_dump_context : public String_dump
-{
- public:
- Ast_dump_context(std::ostream* out = NULL, bool dump_subblocks = true);
-
- // Initialize the dump context.
- void
- dump(Gogo*, const char* basename);
-
- // Dump spaces to dumpfile as indentation.
- void
- print_indent();
-
- // Increase current indentation for print_indent().
- void
- indent()
- { ++this->indent_;}
-
- // Decrease current indentation for print_indent().
- void
- unindent()
- { --this->indent_;}
-
- // Whether subblocks should be dumped or not.
- bool
- dump_subblocks()
- { return this->dump_subblocks_; }
-
- // Get dump output stream.
- std::ostream&
- ostream()
- { return *this->ostream_;}
-
- // Dump a Block to dump file.
- void
- dump_block(Block*);
-
- // Dump a type to dump file.
- void
- dump_type(const Type*);
-
- // Dump an expression to dump file.
- void
- dump_expression(const Expression*);
-
- // Dump an expression list to dump file.
- void
- dump_expression_list(const Expression_list*, bool as_pairs = false);
-
- // Dump a typed identifier to dump file.
- void
- dump_typed_identifier(const Typed_identifier*);
-
- // Dump a typed identifier list to dump file.
- void
- dump_typed_identifier_list(const Typed_identifier_list*);
-
- // Dump temporary variable name to dump file.
- void
- dump_temp_variable_name(const Statement*);
-
- // Dump unamed lable name to dump file.
- void
- dump_label_name(const Unnamed_label*);
-
- // Dump operator symbol to dump file.
- void
- dump_operator(Operator);
-
- // Implementation of String_dump interface.
- void
- write_c_string(const char*);
-
- // Implements the String_dump interface.
- void
- write_string(const std::string& s);
-
- // Dump statement to stream.
- static void
- dump_to_stream(const Statement*, std::ostream*);
-
- // Dump expression to stream.
- static void
- dump_to_stream(const Expression* expr, std::ostream* out);
-
- private:
- // Current indent level.
- int indent_;
-
- // Indentation offset.
- static const int offset_;
-
- // Whether subblocks of composite statements should be dumped or not.
- bool dump_subblocks_;
-
- // Stream on output dump file.
- std::ostream* ostream_;
-
- Gogo* gogo_;
-};
-
-#endif // GO_AST_DUMP_H
diff --git a/gcc-4.8.1/gcc/go/gofrontend/backend.h b/gcc-4.8.1/gcc/go/gofrontend/backend.h
deleted file mode 100644
index fe6db743c..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/backend.h
+++ /dev/null
@@ -1,479 +0,0 @@
-// backend.h -- Go frontend interface to backend -*- C++ -*-
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_BACKEND_H
-#define GO_BACKEND_H
-
-// Pointers to these types are created by the backend, passed to the
-// frontend, and passed back to the backend. The types must be
-// defined by the backend using these names.
-
-// The backend representation of a type.
-class Btype;
-
-// The backend represention of an expression.
-class Bexpression;
-
-// The backend representation of a statement.
-class Bstatement;
-
-// The backend representation of a function definition.
-class Bfunction;
-
-// The backend representation of a block.
-class Bblock;
-
-// The backend representation of a variable.
-class Bvariable;
-
-// The backend representation of a label.
-class Blabel;
-
-// The backend interface. This is a pure abstract class that a
-// specific backend will implement.
-
-class Backend
-{
- public:
- virtual ~Backend() { }
-
- // Name/type/location. Used for function parameters, struct fields,
- // interface methods.
- struct Btyped_identifier
- {
- std::string name;
- Btype* btype;
- Location location;
-
- Btyped_identifier()
- : name(), btype(NULL), location(UNKNOWN_LOCATION)
- { }
-
- Btyped_identifier(const std::string& a_name, Btype* a_btype,
- Location a_location)
- : name(a_name), btype(a_btype), location(a_location)
- { }
- };
-
- // Types.
-
- // Produce an error type. Actually the backend could probably just
- // crash if this is called.
- virtual Btype*
- error_type() = 0;
-
- // Get a void type. This is used in (at least) two ways: 1) as the
- // return type of a function with no result parameters; 2)
- // unsafe.Pointer is represented as *void.
- virtual Btype*
- void_type() = 0;
-
- // Get the unnamed boolean type.
- virtual Btype*
- bool_type() = 0;
-
- // Get an unnamed integer type with the given signedness and number
- // of bits.
- virtual Btype*
- integer_type(bool is_unsigned, int bits) = 0;
-
- // Get an unnamed floating point type with the given number of bits
- // (32 or 64).
- virtual Btype*
- float_type(int bits) = 0;
-
- // Get an unnamed complex type with the given number of bits (64 or 128).
- virtual Btype*
- complex_type(int bits) = 0;
-
- // Get a pointer type.
- virtual Btype*
- pointer_type(Btype* to_type) = 0;
-
- // Get a function type. The receiver, parameter, and results are
- // generated from the types in the Function_type. The Function_type
- // is provided so that the names are available.
- virtual Btype*
- function_type(const Btyped_identifier& receiver,
- const std::vector<Btyped_identifier>& parameters,
- const std::vector<Btyped_identifier>& results,
- Location location) = 0;
-
- // Get a struct type.
- virtual Btype*
- struct_type(const std::vector<Btyped_identifier>& fields) = 0;
-
- // Get an array type.
- virtual Btype*
- array_type(Btype* element_type, Bexpression* length) = 0;
-
- // Create a placeholder pointer type. This is used for a named
- // pointer type, since in Go a pointer type may refer to itself.
- // NAME is the name of the type, and the location is where the named
- // type is defined. This function is also used for unnamed function
- // types with multiple results, in which case the type has no name
- // and NAME will be empty. FOR_FUNCTION is true if this is for a Go
- // function type, which corresponds to a C/C++ pointer to function
- // type. The return value will later be passed as the first
- // parameter to set_placeholder_pointer_type or
- // set_placeholder_function_type.
- virtual Btype*
- placeholder_pointer_type(const std::string& name, Location,
- bool for_function) = 0;
-
- // Fill in a placeholder pointer type as a pointer. This takes a
- // type returned by placeholder_pointer_type and arranges for it to
- // point to the type that TO_TYPE points to (that is, PLACEHOLDER
- // becomes the same type as TO_TYPE). Returns true on success,
- // false on failure.
- virtual bool
- set_placeholder_pointer_type(Btype* placeholder, Btype* to_type) = 0;
-
- // Fill in a placeholder pointer type as a function. This takes a
- // type returned by placeholder_pointer_type and arranges for it to
- // become a real Go function type (which corresponds to a C/C++
- // pointer to function type). FT will be something returned by the
- // function_type method. Returns true on success, false on failure.
- virtual bool
- set_placeholder_function_type(Btype* placeholder, Btype* ft) = 0;
-
- // Create a placeholder struct type. This is used for a named
- // struct type, as with placeholder_pointer_type. It is also used
- // for interface types, in which case NAME will be the empty string.
- virtual Btype*
- placeholder_struct_type(const std::string& name, Location) = 0;
-
- // Fill in a placeholder struct type. This takes a type returned by
- // placeholder_struct_type and arranges for it to become a real
- // struct type. The parameter is as for struct_type. Returns true
- // on success, false on failure.
- virtual bool
- set_placeholder_struct_type(Btype* placeholder,
- const std::vector<Btyped_identifier>& fields)
- = 0;
-
- // Create a placeholder array type. This is used for a named array
- // type, as with placeholder_pointer_type, to handle cases like
- // type A []*A.
- virtual Btype*
- placeholder_array_type(const std::string& name, Location) = 0;
-
- // Fill in a placeholder array type. This takes a type returned by
- // placeholder_array_type and arranges for it to become a real array
- // type. The parameters are as for array_type. Returns true on
- // success, false on failure.
- virtual bool
- set_placeholder_array_type(Btype* placeholder, Btype* element_type,
- Bexpression* length) = 0;
-
- // Return a named version of a type. The location is the location
- // of the type definition. This will not be called for a type
- // created via placeholder_pointer_type, placeholder_struct_type, or
- // placeholder_array_type.. (It may be called for a pointer,
- // struct, or array type in a case like "type P *byte; type Q P".)
- virtual Btype*
- named_type(const std::string& name, Btype*, Location) = 0;
-
- // Create a marker for a circular pointer type. Go pointer and
- // function types can refer to themselves in ways that are not
- // permitted in C/C++. When a circular type is found, this function
- // is called for the circular reference. This permits the backend
- // to decide how to handle such a type. PLACEHOLDER is the
- // placeholder type which has already been created; if the backend
- // is prepared to handle a circular pointer type, it may simply
- // return PLACEHOLDER. FOR_FUNCTION is true if this is for a
- // function type.
- //
- // For "type P *P" the sequence of calls will be
- // bt1 = placeholder_pointer_type();
- // bt2 = circular_pointer_type(bt1, false);
- // set_placeholder_pointer_type(bt1, bt2);
- virtual Btype*
- circular_pointer_type(Btype* placeholder, bool for_function) = 0;
-
- // Return whether the argument could be a special type created by
- // circular_pointer_type. This is used to introduce explicit type
- // conversions where needed. If circular_pointer_type returns its
- // PLACEHOLDER parameter, this may safely always return false.
- virtual bool
- is_circular_pointer_type(Btype*) = 0;
-
- // Return the size of a type.
- virtual size_t
- type_size(Btype*) = 0;
-
- // Return the alignment of a type.
- virtual size_t
- type_alignment(Btype*) = 0;
-
- // Return the alignment of a struct field of this type. This is
- // normally the same as type_alignment, but not always.
- virtual size_t
- type_field_alignment(Btype*) = 0;
-
- // Return the offset of field INDEX in a struct type. INDEX is the
- // entry in the FIELDS std::vector parameter of struct_type or
- // set_placeholder_struct_type.
- virtual size_t
- type_field_offset(Btype*, size_t index) = 0;
-
- // Expressions.
-
- // Return an expression for a zero value of the given type. This is
- // used for cases such as local variable initialization and
- // converting nil to other types.
- virtual Bexpression*
- zero_expression(Btype*) = 0;
-
- // Statements.
-
- // Create an error statement. This is used for cases which should
- // not occur in a correct program, in order to keep the compilation
- // going without crashing.
- virtual Bstatement*
- error_statement() = 0;
-
- // Create an expression statement.
- virtual Bstatement*
- expression_statement(Bexpression*) = 0;
-
- // Create a variable initialization statement. This initializes a
- // local variable at the point in the program flow where it is
- // declared.
- virtual Bstatement*
- init_statement(Bvariable* var, Bexpression* init) = 0;
-
- // Create an assignment statement.
- virtual Bstatement*
- assignment_statement(Bexpression* lhs, Bexpression* rhs,
- Location) = 0;
-
- // Create a return statement, passing the representation of the
- // function and the list of values to return.
- virtual Bstatement*
- return_statement(Bfunction*, const std::vector<Bexpression*>&,
- Location) = 0;
-
- // Create an if statement. ELSE_BLOCK may be NULL.
- virtual Bstatement*
- if_statement(Bexpression* condition, Bblock* then_block, Bblock* else_block,
- Location) = 0;
-
- // Create a switch statement where the case values are constants.
- // CASES and STATEMENTS must have the same number of entries. If
- // VALUE matches any of the list in CASES[i], which will all be
- // integers, then STATEMENTS[i] is executed. STATEMENTS[i] will
- // either end with a goto statement or will fall through into
- // STATEMENTS[i + 1]. CASES[i] is empty for the default clause,
- // which need not be last.
- virtual Bstatement*
- switch_statement(Bexpression* value,
- const std::vector<std::vector<Bexpression*> >& cases,
- const std::vector<Bstatement*>& statements,
- Location) = 0;
-
- // Create a single statement from two statements.
- virtual Bstatement*
- compound_statement(Bstatement*, Bstatement*) = 0;
-
- // Create a single statement from a list of statements.
- virtual Bstatement*
- statement_list(const std::vector<Bstatement*>&) = 0;
-
- // Blocks.
-
- // Create a block. The frontend will call this function when it
- // starts converting a block within a function. FUNCTION is the
- // current function. ENCLOSING is the enclosing block; it will be
- // NULL for the top-level block in a function. VARS is the list of
- // local variables defined within this block; each entry will be
- // created by the local_variable function. START_LOCATION is the
- // location of the start of the block, more or less the location of
- // the initial curly brace. END_LOCATION is the location of the end
- // of the block, more or less the location of the final curly brace.
- // The statements will be added after the block is created.
- virtual Bblock*
- block(Bfunction* function, Bblock* enclosing,
- const std::vector<Bvariable*>& vars,
- Location start_location, Location end_location) = 0;
-
- // Add the statements to a block. The block is created first. Then
- // the statements are created. Then the statements are added to the
- // block. This will called exactly once per block. The vector may
- // be empty if there are no statements.
- virtual void
- block_add_statements(Bblock*, const std::vector<Bstatement*>&) = 0;
-
- // Return the block as a statement. This is used to include a block
- // in a list of statements.
- virtual Bstatement*
- block_statement(Bblock*) = 0;
-
- // Variables.
-
- // Create an error variable. This is used for cases which should
- // not occur in a correct program, in order to keep the compilation
- // going without crashing.
- virtual Bvariable*
- error_variable() = 0;
-
- // Create a global variable. PACKAGE_NAME is the name of the
- // package where the variable is defined. PKGPATH is the package
- // path for that package, from the -fgo-pkgpath or -fgo-prefix
- // option. NAME is the name of the variable. BTYPE is the type of
- // the variable. IS_EXTERNAL is true if the variable is defined in
- // some other package. IS_HIDDEN is true if the variable is not
- // exported (name begins with a lower case letter).
- // IN_UNIQUE_SECTION is true if the variable should be put into a
- // unique section if possible; this is intended to permit the linker
- // to garbage collect the variable if it is not referenced.
- // LOCATION is where the variable was defined.
- virtual Bvariable*
- global_variable(const std::string& package_name,
- const std::string& pkgpath,
- const std::string& name,
- Btype* btype,
- bool is_external,
- bool is_hidden,
- bool in_unique_section,
- Location location) = 0;
-
- // A global variable will 1) be initialized to zero, or 2) be
- // initialized to a constant value, or 3) be initialized in the init
- // function. In case 2, the frontend will call
- // global_variable_set_init to set the initial value. If this is
- // not called, the backend should initialize a global variable to 0.
- // The init function may then assign a value to it.
- virtual void
- global_variable_set_init(Bvariable*, Bexpression*) = 0;
-
- // Create a local variable. The frontend will create the local
- // variables first, and then create the block which contains them.
- // FUNCTION is the function in which the variable is defined. NAME
- // is the name of the variable. TYPE is the type. IS_ADDRESS_TAKEN
- // is true if the address of this variable is taken (this implies
- // that the address does not escape the function, as otherwise the
- // variable would be on the heap). LOCATION is where the variable
- // is defined. For each local variable the frontend will call
- // init_statement to set the initial value.
- virtual Bvariable*
- local_variable(Bfunction* function, const std::string& name, Btype* type,
- bool is_address_taken, Location location) = 0;
-
- // Create a function parameter. This is an incoming parameter, not
- // a result parameter (result parameters are treated as local
- // variables). The arguments are as for local_variable.
- virtual Bvariable*
- parameter_variable(Bfunction* function, const std::string& name,
- Btype* type, bool is_address_taken,
- Location location) = 0;
-
- // Create a temporary variable. A temporary variable has no name,
- // just a type. We pass in FUNCTION and BLOCK in case they are
- // needed. If INIT is not NULL, the variable should be initialized
- // to that value. Otherwise the initial value is irrelevant--the
- // backend does not have to explicitly initialize it to zero.
- // ADDRESS_IS_TAKEN is true if the programs needs to take the
- // address of this temporary variable. LOCATION is the location of
- // the statement or expression which requires creating the temporary
- // variable, and may not be very useful. This function should
- // return a variable which can be referenced later and should set
- // *PSTATEMENT to a statement which initializes the variable.
- virtual Bvariable*
- temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression* init,
- bool address_is_taken, Location location,
- Bstatement** pstatement) = 0;
-
- // Create a named immutable initialized data structure. This is
- // used for type descriptors and map descriptors. This returns a
- // Bvariable because it corresponds to an initialized const global
- // variable in C.
- //
- // NAME is the name to use for the initialized global variable which
- // this call will create.
- //
- // IS_COMMON is true if NAME may be defined by several packages, and
- // the linker should merge all such definitions. If IS_COMMON is
- // false, NAME should be defined in only one file. In general
- // IS_COMMON will be true for the type descriptor of an unnamed type
- // or a builtin type.
- //
- // TYPE will be a struct type; the type of the returned expression
- // must be a pointer to this struct type.
- //
- // We must create the named structure before we know its
- // initializer, because the initializer may refer to its own
- // address. After calling this the frontend will call
- // immutable_struct_set_init.
- virtual Bvariable*
- immutable_struct(const std::string& name, bool is_common, Btype* type,
- Location) = 0;
-
- // Set the initial value of a variable created by immutable_struct.
- // The NAME, IS_COMMON, TYPE, and location parameters are the same
- // ones passed to immutable_struct. INITIALIZER will be a composite
- // literal of type TYPE. It will not contain any function calls or
- // anything else which can not be put into a read-only data section.
- // It may contain the address of variables created by
- // immutable_struct.
- virtual void
- immutable_struct_set_init(Bvariable*, const std::string& name,
- bool is_common, Btype* type, Location,
- Bexpression* initializer) = 0;
-
- // Create a reference to a named immutable initialized data
- // structure defined in some other package. This will be a
- // structure created by a call to immutable_struct with the same
- // NAME and TYPE and with IS_COMMON passed as false. This
- // corresponds to an extern const global variable in C.
- virtual Bvariable*
- immutable_struct_reference(const std::string& name, Btype* type,
- Location) = 0;
-
- // Labels.
-
- // Create a new label. NAME will be empty if this is a label
- // created by the frontend for a loop construct. The location is
- // where the the label is defined.
- virtual Blabel*
- label(Bfunction*, const std::string& name, Location) = 0;
-
- // Create a statement which defines a label. This statement will be
- // put into the codestream at the point where the label should be
- // defined.
- virtual Bstatement*
- label_definition_statement(Blabel*) = 0;
-
- // Create a goto statement to a label.
- virtual Bstatement*
- goto_statement(Blabel*, Location) = 0;
-
- // Create an expression for the address of a label. This is used to
- // get the return address of a deferred function which may call
- // recover.
- virtual Bexpression*
- label_address(Blabel*, Location) = 0;
-};
-
-// The backend interface has to define this function.
-
-extern Backend* go_get_backend();
-
-// FIXME: Temporary helper functions while converting to new backend
-// interface.
-
-extern Btype* tree_to_type(tree);
-extern Bexpression* tree_to_expr(tree);
-extern Bstatement* tree_to_stat(tree);
-extern Bfunction* tree_to_function(tree);
-extern Bblock* tree_to_block(tree);
-extern tree type_to_tree(Btype*);
-extern tree expr_to_tree(Bexpression*);
-extern tree stat_to_tree(Bstatement*);
-extern tree block_to_tree(Bblock*);
-extern tree var_to_tree(Bvariable*);
-
-#endif // !defined(GO_BACKEND_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/dataflow.cc b/gcc-4.8.1/gcc/go/gofrontend/dataflow.cc
deleted file mode 100644
index 572ab3631..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/dataflow.cc
+++ /dev/null
@@ -1,278 +0,0 @@
-// dataflow.cc -- Go frontend dataflow.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "gogo.h"
-#include "expressions.h"
-#include "statements.h"
-#include "dataflow.h"
-
-// This class is used to traverse the tree to look for uses of
-// variables.
-
-class Dataflow_traverse_expressions : public Traverse
-{
- public:
- Dataflow_traverse_expressions(Dataflow* dataflow, Statement* statement)
- : Traverse(traverse_blocks | traverse_expressions),
- dataflow_(dataflow), statement_(statement)
- { }
-
- protected:
- // Only look at top-level expressions: do not descend into blocks.
- // They will be examined via Dataflow_traverse_statements.
- int
- block(Block*)
- { return TRAVERSE_SKIP_COMPONENTS; }
-
- int
- expression(Expression**);
-
- private:
- // The dataflow information.
- Dataflow* dataflow_;
- // The Statement in which we are looking.
- Statement* statement_;
-};
-
-// Given an expression, return the Named_object that it refers to, if
-// it is a local variable.
-
-static Named_object*
-get_var(Expression* expr)
-{
- Var_expression* ve = expr->var_expression();
- if (ve == NULL)
- return NULL;
- Named_object* no = ve->named_object();
- go_assert(no->is_variable() || no->is_result_variable());
- if (no->is_variable() && no->var_value()->is_global())
- return NULL;
- return no;
-}
-
-// Look for a reference to a variable in an expression.
-
-int
-Dataflow_traverse_expressions::expression(Expression** expr)
-{
- Named_object* no = get_var(*expr);
- if (no != NULL)
- this->dataflow_->add_ref(no, this->statement_);
- return TRAVERSE_CONTINUE;
-}
-
-// This class is used to handle an assignment statement.
-
-class Dataflow_traverse_assignment : public Traverse_assignments
-{
- public:
- Dataflow_traverse_assignment(Dataflow* dataflow, Statement* statement)
- : dataflow_(dataflow), statement_(statement)
- { }
-
- protected:
- void
- initialize_variable(Named_object*);
-
- void
- assignment(Expression** lhs, Expression** rhs);
-
- void
- value(Expression**, bool, bool);
-
- private:
- // The dataflow information.
- Dataflow* dataflow_;
- // The Statement in which we are looking.
- Statement* statement_;
-};
-
-// Handle a variable initialization.
-
-void
-Dataflow_traverse_assignment::initialize_variable(Named_object* var)
-{
- Expression* init = var->var_value()->init();
- this->dataflow_->add_def(var, init, this->statement_, true);
- if (init != NULL)
- {
- Expression* e = init;
- this->value(&e, true, true);
- go_assert(e == init);
- }
-}
-
-// Handle an assignment in a statement.
-
-void
-Dataflow_traverse_assignment::assignment(Expression** plhs, Expression** prhs)
-{
- Named_object* no = get_var(*plhs);
- if (no != NULL)
- {
- Expression* rhs = prhs == NULL ? NULL : *prhs;
- this->dataflow_->add_def(no, rhs, this->statement_, false);
- }
- else
- {
- // If this is not a variable it may be some computed lvalue, and
- // we want to look for references to variables in that lvalue.
- this->value(plhs, false, false);
- }
- if (prhs != NULL)
- this->value(prhs, true, false);
-}
-
-// Handle a value in a statement.
-
-void
-Dataflow_traverse_assignment::value(Expression** pexpr, bool, bool)
-{
- Named_object* no = get_var(*pexpr);
- if (no != NULL)
- this->dataflow_->add_ref(no, this->statement_);
- else
- {
- Dataflow_traverse_expressions dte(this->dataflow_, this->statement_);
- Expression::traverse(pexpr, &dte);
- }
-}
-
-// This class is used to traverse the tree to look for statements.
-
-class Dataflow_traverse_statements : public Traverse
-{
- public:
- Dataflow_traverse_statements(Dataflow* dataflow)
- : Traverse(traverse_statements),
- dataflow_(dataflow)
- { }
-
- protected:
- int
- statement(Block*, size_t* pindex, Statement*);
-
- private:
- // The dataflow information.
- Dataflow* dataflow_;
-};
-
-// For each Statement, we look for expressions.
-
-int
-Dataflow_traverse_statements::statement(Block* block, size_t* pindex,
- Statement *statement)
-{
- Dataflow_traverse_assignment dta(this->dataflow_, statement);
- if (!statement->traverse_assignments(&dta))
- {
- Dataflow_traverse_expressions dte(this->dataflow_, statement);
- statement->traverse(block, pindex, &dte);
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Compare variables.
-
-bool
-Dataflow::Compare_vars::operator()(const Named_object* no1,
- const Named_object* no2) const
-{
- if (no1->name() < no2->name())
- return true;
- if (no1->name() > no2->name())
- return false;
-
- // We can have two different variables with the same name.
- Location loc1 = no1->location();
- Location loc2 = no2->location();
- if (loc1 < loc2)
- return false;
- if (loc1 > loc2)
- return true;
-
- if (no1 == no2)
- return false;
-
- // We can't have two variables with the same name in the same
- // location.
- go_unreachable();
-}
-
-// Class Dataflow.
-
-Dataflow::Dataflow()
- : defs_(), refs_()
-{
-}
-
-// Build the dataflow information.
-
-void
-Dataflow::initialize(Gogo* gogo)
-{
- Dataflow_traverse_statements dts(this);
- gogo->traverse(&dts);
-}
-
-// Add a definition of a variable.
-
-void
-Dataflow::add_def(Named_object* var, Expression* val, Statement* statement,
- bool is_init)
-{
- Defs* defnull = NULL;
- std::pair<Defmap::iterator, bool> ins =
- this->defs_.insert(std::make_pair(var, defnull));
- if (ins.second)
- ins.first->second = new Defs;
- Def def;
- def.statement = statement;
- def.val = val;
- def.is_init = is_init;
- ins.first->second->push_back(def);
-}
-
-// Add a reference to a variable.
-
-void
-Dataflow::add_ref(Named_object* var, Statement* statement)
-{
- Refs* refnull = NULL;
- std::pair<Refmap::iterator, bool> ins =
- this->refs_.insert(std::make_pair(var, refnull));
- if (ins.second)
- ins.first->second = new Refs;
- Ref ref;
- ref.statement = statement;
- ins.first->second->push_back(ref);
-}
-
-// Return the definitions of a variable.
-
-const Dataflow::Defs*
-Dataflow::find_defs(Named_object* var) const
-{
- Defmap::const_iterator p = this->defs_.find(var);
- if (p == this->defs_.end())
- return NULL;
- else
- return p->second;
-}
-
-// Return the references of a variable.
-
-const Dataflow::Refs*
-Dataflow::find_refs(Named_object* var) const
-{
- Refmap::const_iterator p = this->refs_.find(var);
- if (p == this->refs_.end())
- return NULL;
- else
- return p->second;
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/dataflow.h b/gcc-4.8.1/gcc/go/gofrontend/dataflow.h
deleted file mode 100644
index a75c8e661..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/dataflow.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// dataflow.h -- Go frontend dataflow. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_DATAFLOW_H
-#define GO_DATAFLOW_H
-
-class Expression;
-class Named_object;
-class Statement;
-
-// Dataflow information about the Go program.
-
-class Dataflow
-{
- public:
- // A variable definition.
- struct Def
- {
- // The statement where the variable is defined.
- Statement* statement;
- // The value to which the variable is set. This may be NULL.
- Expression* val;
- // Whether this is an initialization of the variable.
- bool is_init;
- };
-
- // A variable reference.
- struct Ref
- {
- // The statement where the variable is referenced.
- Statement* statement;
- };
-
- // A list of defs.
- typedef std::vector<Def> Defs;
-
- // A list of refs.
- typedef std::vector<Ref> Refs;
-
- Dataflow();
-
- // Initialize the dataflow information.
- void
- initialize(Gogo*);
-
- // Add a definition of a variable. STATEMENT assigns a value to
- // VAR. VAL is the value if it is known, NULL otherwise.
- void
- add_def(Named_object* var, Expression* val, Statement* statement,
- bool is_init);
-
- // Add a reference to a variable. VAR is the variable, and
- // STATEMENT is the statement which refers to it.
- void
- add_ref(Named_object* var, Statement* statement);
-
- // Return the definitions of VAR--the places where it is set.
- const Defs*
- find_defs(Named_object* var) const;
-
- // Return the references to VAR--the places where it is used.
- const Refs*
- find_refs(Named_object* var) const;
-
- private:
- // Order variables in the map.
- struct Compare_vars
- {
- bool
- operator()(const Named_object*, const Named_object*) const;
- };
-
- // Map from variables to a list of defs of the variable. We use a
- // map rather than a hash table because the order in which we
- // process variables may affect the resulting code.
- typedef std::map<Named_object*, Defs*, Compare_vars> Defmap;
-
- // Map from variables to a list of refs to the vairable.
- typedef std::map<Named_object*, Refs*, Compare_vars> Refmap;
-
- // Variable defs.
- Defmap defs_;
- // Variable refs;
- Refmap refs_;
-};
-
-
-#endif // !defined(GO_DATAFLOW_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/export.cc b/gcc-4.8.1/gcc/go/gofrontend/export.cc
deleted file mode 100644
index 13c61a589..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/export.cc
+++ /dev/null
@@ -1,491 +0,0 @@
-// export.cc -- Export declarations in Go frontend.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "sha1.h"
-
-#include "go-c.h"
-
-#include "gogo.h"
-#include "types.h"
-#include "statements.h"
-#include "export.h"
-
-// This file handles exporting global declarations.
-
-// Class Export.
-
-// Version 1 magic number.
-
-const int Export::v1_magic_len;
-
-const char Export::v1_magic[Export::v1_magic_len] =
- {
- 'v', '1', ';', '\n'
- };
-
-const int Export::v1_checksum_len;
-
-// Constructor.
-
-Export::Export(Stream* stream)
- : stream_(stream), type_refs_(), type_index_(1), packages_()
-{
-}
-
-// A functor to sort Named_object pointers by name.
-
-struct Sort_bindings
-{
- bool
- operator()(const Named_object* n1, const Named_object* n2) const
- { return n1->name() < n2->name(); }
-};
-
-// Return true if we should export NO.
-
-static bool
-should_export(Named_object* no)
-{
- // We only export objects which are locally defined.
- if (no->package() != NULL)
- return false;
-
- // We don't export packages.
- if (no->is_package())
- return false;
-
- // We don't export hidden names.
- if (Gogo::is_hidden_name(no->name()))
- return false;
-
- // We don't export nested functions.
- if (no->is_function() && no->func_value()->enclosing() != NULL)
- return false;
-
- // We don't export thunks.
- if (no->is_function() && Gogo::is_thunk(no))
- return false;
-
- // Methods are exported with the type, not here.
- if (no->is_function()
- && no->func_value()->type()->is_method())
- return false;
- if (no->is_function_declaration()
- && no->func_declaration_value()->type()->is_method())
- return false;
-
- // Don't export dummy global variables created for initializers when
- // used with sinks.
- if (no->is_variable() && no->name()[0] == '_' && no->name()[1] == '.')
- return false;
-
- return true;
-}
-
-// Export those identifiers marked for exporting.
-
-void
-Export::export_globals(const std::string& package_name,
- const std::string& pkgpath,
- int package_priority,
- const std::map<std::string, Package*>& imports,
- const std::string& import_init_fn,
- const std::set<Import_init>& imported_init_fns,
- const Bindings* bindings)
-{
- // If there have been any errors so far, don't try to export
- // anything. That way the export code doesn't have to worry about
- // mismatched types or other confusions.
- if (saw_errors())
- return;
-
- // Export the symbols in sorted order. That will reduce cases where
- // irrelevant changes to the source code affect the exported
- // interface.
- std::vector<Named_object*> exports;
- exports.reserve(bindings->size_definitions());
-
- for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
- p != bindings->end_definitions();
- ++p)
- if (should_export(*p))
- exports.push_back(*p);
-
- for (Bindings::const_declarations_iterator p =
- bindings->begin_declarations();
- p != bindings->end_declarations();
- ++p)
- {
- // We export a function declaration as it may be implemented in
- // supporting C code. We do not export type declarations.
- if (p->second->is_function_declaration()
- && should_export(p->second))
- exports.push_back(p->second);
- }
-
- std::sort(exports.begin(), exports.end(), Sort_bindings());
-
- // Although the export data is readable, at least this version is,
- // it is conceptually a binary format. Start with a four byte
- // verison number.
- this->write_bytes(Export::v1_magic, Export::v1_magic_len);
-
- // The package name.
- this->write_c_string("package ");
- this->write_string(package_name);
- this->write_c_string(";\n");
-
- // The package path, used for all global symbols.
- this->write_c_string("pkgpath ");
- this->write_string(pkgpath);
- this->write_c_string(";\n");
-
- // The package priority.
- char buf[100];
- snprintf(buf, sizeof buf, "priority %d;\n", package_priority);
- this->write_c_string(buf);
-
- this->write_imports(imports);
-
- this->write_imported_init_fns(package_name, package_priority, import_init_fn,
- imported_init_fns);
-
- // FIXME: It might be clever to add something about the processor
- // and ABI being used, although ideally any problems in that area
- // would be caught by the linker.
-
- for (std::vector<Named_object*>::const_iterator p = exports.begin();
- p != exports.end();
- ++p)
- (*p)->export_named_object(this);
-
- std::string checksum = this->stream_->checksum();
- std::string s = "checksum ";
- for (std::string::const_iterator p = checksum.begin();
- p != checksum.end();
- ++p)
- {
- unsigned char c = *p;
- unsigned int dig = c >> 4;
- s += dig < 10 ? '0' + dig : 'A' + dig - 10;
- dig = c & 0xf;
- s += dig < 10 ? '0' + dig : 'A' + dig - 10;
- }
- s += ";\n";
- this->stream_->write_checksum(s);
-}
-
-// Sort imported packages.
-
-static bool
-import_compare(const std::pair<std::string, Package*>& a,
- const std::pair<std::string, Package*>& b)
-{
- return a.first < b.first;
-}
-
-// Write out the imported packages.
-
-void
-Export::write_imports(const std::map<std::string, Package*>& imports)
-{
- // Sort the imports for more consistent output.
- std::vector<std::pair<std::string, Package*> > imp;
- for (std::map<std::string, Package*>::const_iterator p = imports.begin();
- p != imports.end();
- ++p)
- imp.push_back(std::make_pair(p->first, p->second));
-
- std::sort(imp.begin(), imp.end(), import_compare);
-
- for (std::vector<std::pair<std::string, Package*> >::const_iterator p =
- imp.begin();
- p != imp.end();
- ++p)
- {
- this->write_c_string("import ");
- this->write_string(p->second->package_name());
- this->write_c_string(" ");
- this->write_string(p->second->pkgpath());
- this->write_c_string(" \"");
- this->write_string(p->first);
- this->write_c_string("\";\n");
-
- this->packages_.insert(p->second);
- }
-}
-
-// Write out the initialization functions which need to run for this
-// package.
-
-void
-Export::write_imported_init_fns(
- const std::string& package_name,
- int priority,
- const std::string& import_init_fn,
- const std::set<Import_init>& imported_init_fns)
-{
- if (import_init_fn.empty() && imported_init_fns.empty())
- return;
-
- this->write_c_string("init");
-
- if (!import_init_fn.empty())
- {
- this->write_c_string(" ");
- this->write_string(package_name);
- this->write_c_string(" ");
- this->write_string(import_init_fn);
- char buf[100];
- snprintf(buf, sizeof buf, " %d", priority);
- this->write_c_string(buf);
- }
-
- if (!imported_init_fns.empty())
- {
- // Sort the list of functions for more consistent output.
- std::vector<Import_init> v;
- for (std::set<Import_init>::const_iterator p = imported_init_fns.begin();
- p != imported_init_fns.end();
- ++p)
- v.push_back(*p);
- std::sort(v.begin(), v.end());
-
- for (std::vector<Import_init>::const_iterator p = v.begin();
- p != v.end();
- ++p)
- {
- this->write_c_string(" ");
- this->write_string(p->package_name());
- this->write_c_string(" ");
- this->write_string(p->init_name());
- char buf[100];
- snprintf(buf, sizeof buf, " %d", p->priority());
- this->write_c_string(buf);
- }
- }
-
- this->write_c_string(";\n");
-}
-
-// Write a name to the export stream.
-
-void
-Export::write_name(const std::string& name)
-{
- if (name.empty())
- this->write_c_string("?");
- else
- this->write_string(Gogo::message_name(name));
-}
-
-// Export a type. We have to ensure that on import we create a single
-// Named_type node for each named type. We do this by keeping a hash
-// table mapping named types to reference numbers. The first time we
-// see a named type we assign it a reference number by making an entry
-// in the hash table. If we see it again, we just refer to the
-// reference number.
-
-// Named types are, of course, associated with packages. Note that we
-// may see a named type when importing one package, and then later see
-// the same named type when importing a different package. The home
-// package may or may not be imported during this compilation. The
-// reference number scheme has to get this all right. Basic approach
-// taken from "On the Linearization of Graphs and Writing Symbol
-// Files" by Robert Griesemer.
-
-void
-Export::write_type(const Type* type)
-{
- // We don't want to assign a reference number to a forward
- // declaration to a type which was defined later.
- type = type->forwarded();
-
- Type_refs::const_iterator p = this->type_refs_.find(type);
- if (p != this->type_refs_.end())
- {
- // This type was already in the table.
- int index = p->second;
- go_assert(index != 0);
- char buf[30];
- snprintf(buf, sizeof buf, "<type %d>", index);
- this->write_c_string(buf);
- return;
- }
-
- const Named_type* named_type = type->named_type();
- const Forward_declaration_type* forward = type->forward_declaration_type();
-
- int index = this->type_index_;
- ++this->type_index_;
-
- char buf[30];
- snprintf(buf, sizeof buf, "<type %d ", index);
- this->write_c_string(buf);
-
- if (named_type != NULL || forward != NULL)
- {
- const Named_object* named_object;
- if (named_type != NULL)
- {
- // The builtin types should have been predefined.
- go_assert(!Linemap::is_predeclared_location(named_type->location())
- || (named_type->named_object()->package()->package_name()
- == "unsafe"));
- named_object = named_type->named_object();
- }
- else
- named_object = forward->named_object();
-
- const Package* package = named_object->package();
-
- std::string s = "\"";
- if (package != NULL && !Gogo::is_hidden_name(named_object->name()))
- {
- s += package->pkgpath();
- s += '.';
- }
- s += named_object->name();
- s += "\" ";
- this->write_string(s);
-
- // It is possible that this type was imported indirectly, and is
- // not in a package in the import list. If we have not
- // mentioned this package before, write out the package name
- // here so that any package importing this one will know it.
- if (package != NULL
- && this->packages_.find(package) == this->packages_.end())
- {
- this->write_c_string("\"");
- this->write_string(package->package_name());
- this->packages_.insert(package);
- this->write_c_string("\" ");
- }
-
- // We must add a named type to the table now, since the
- // definition of the type may refer to the named type via a
- // pointer.
- this->type_refs_[type] = index;
- }
-
- type->export_type(this);
-
- this->write_c_string(">");
-
- if (named_type == NULL)
- this->type_refs_[type] = index;
-}
-
-// Add the builtin types to the export table.
-
-void
-Export::register_builtin_types(Gogo* gogo)
-{
- this->register_builtin_type(gogo, "int8", BUILTIN_INT8);
- this->register_builtin_type(gogo, "int16", BUILTIN_INT16);
- this->register_builtin_type(gogo, "int32", BUILTIN_INT32);
- this->register_builtin_type(gogo, "int64", BUILTIN_INT64);
- this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8);
- this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16);
- this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32);
- this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
- this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
- this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
- this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
- this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
- this->register_builtin_type(gogo, "int", BUILTIN_INT);
- this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
- this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
- this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
- this->register_builtin_type(gogo, "string", BUILTIN_STRING);
- this->register_builtin_type(gogo, "error", BUILTIN_ERROR);
- this->register_builtin_type(gogo, "byte", BUILTIN_BYTE);
- this->register_builtin_type(gogo, "rune", BUILTIN_RUNE);
-}
-
-// Register one builtin type in the export table.
-
-void
-Export::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code)
-{
- Named_object* named_object = gogo->lookup_global(name);
- go_assert(named_object != NULL && named_object->is_type());
- std::pair<Type_refs::iterator, bool> ins =
- this->type_refs_.insert(std::make_pair(named_object->type_value(), code));
- go_assert(ins.second);
-
- // We also insert the underlying type. We can see the underlying
- // type at least for string and bool. We skip the type aliases byte
- // and rune here.
- if (code != BUILTIN_BYTE && code != BUILTIN_RUNE)
- {
- Type* real_type = named_object->type_value()->real_type();
- ins = this->type_refs_.insert(std::make_pair(real_type, code));
- go_assert(ins.second);
- }
-}
-
-// Class Export::Stream.
-
-Export::Stream::Stream()
-{
- this->checksum_ = new sha1_ctx;
- memset(this->checksum_, 0, sizeof(sha1_ctx));
- sha1_init_ctx(this->checksum_);
-}
-
-Export::Stream::~Stream()
-{
-}
-
-// Write bytes to the stream. This keeps a checksum of bytes as they
-// go by.
-
-void
-Export::Stream::write_and_sum_bytes(const char* bytes, size_t length)
-{
- sha1_process_bytes(bytes, length, this->checksum_);
- this->do_write(bytes, length);
-}
-
-// Get the checksum.
-
-std::string
-Export::Stream::checksum()
-{
- // Use a union to provide the required alignment.
- union
- {
- char checksum[Export::v1_checksum_len];
- long align;
- } u;
- sha1_finish_ctx(this->checksum_, u.checksum);
- return std::string(u.checksum, Export::v1_checksum_len);
-}
-
-// Write the checksum string to the export data.
-
-void
-Export::Stream::write_checksum(const std::string& s)
-{
- this->do_write(s.data(), s.length());
-}
-
-// Class Stream_to_section.
-
-Stream_to_section::Stream_to_section()
-{
-}
-
-// Write data to a section.
-
-void
-Stream_to_section::do_write(const char* bytes, size_t length)
-{
- go_write_export_data (bytes, length);
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/export.h b/gcc-4.8.1/gcc/go/gofrontend/export.h
deleted file mode 100644
index c6a481051..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/export.h
+++ /dev/null
@@ -1,201 +0,0 @@
-// export.h -- Export declarations in Go frontend. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_EXPORT_H
-#define GO_EXPORT_H
-
-#include "string-dump.h"
-
-struct sha1_ctx;
-class Gogo;
-class Import_init;
-class Bindings;
-class Type;
-class Package;
-
-// Codes used for the builtin types. These are all negative to make
-// them easily distinct from the codes assigned by Export::write_type.
-// Note that these codes may not be changed! Changing them would
-// break existing export data.
-
-enum Builtin_code
-{
- BUILTIN_INT8 = -1,
- BUILTIN_INT16 = -2,
- BUILTIN_INT32 = -3,
- BUILTIN_INT64 = -4,
- BUILTIN_UINT8 = -5,
- BUILTIN_UINT16 = -6,
- BUILTIN_UINT32 = -7,
- BUILTIN_UINT64 = -8,
- BUILTIN_FLOAT32 = -9,
- BUILTIN_FLOAT64 = -10,
- BUILTIN_INT = -11,
- BUILTIN_UINT = -12,
- BUILTIN_UINTPTR = -13,
- BUILTIN_BOOL = -15,
- BUILTIN_STRING = -16,
- BUILTIN_COMPLEX64 = -17,
- BUILTIN_COMPLEX128 = -18,
- BUILTIN_ERROR = -19,
- BUILTIN_BYTE = -20,
- BUILTIN_RUNE = -21,
-
- SMALLEST_BUILTIN_CODE = -21
-};
-
-// This class manages exporting Go declarations. It handles the main
-// loop of exporting. A pointer to this class is also passed to the
-// various specific export implementations.
-
-class Export : public String_dump
-{
- public:
- // The Stream class is an interface used to output the exported
- // information. The caller should instantiate a child of this
- // class.
- class Stream
- {
- public:
- Stream();
- virtual ~Stream();
-
- // Write a string. Implements the String_dump interface.
- void
- write_string(const std::string& s)
- { this->write_and_sum_bytes(s.data(), s.length()); }
-
- // Write a nul terminated string. Implements the String_dump interface.
- void
- write_c_string(const char* s)
- { this->write_and_sum_bytes(s, strlen(s)); }
-
- // Write some bytes.
- void
- write_bytes(const char* bytes, size_t length)
- { this->write_and_sum_bytes(bytes, length); }
-
- // Return the raw bytes of the checksum data.
- std::string
- checksum();
-
- // Write a checksum string to the stream. This will be called at
- // the end of the other output.
- void
- write_checksum(const std::string&);
-
- protected:
- // This function is called with data to export. This data must be
- // made available as a contiguous stream for the importer.
- virtual void
- do_write(const char* bytes, size_t length) = 0;
-
- private:
- void
- write_and_sum_bytes(const char*, size_t);
-
- // The checksum.
- sha1_ctx* checksum_;
- };
-
- Export(Stream*);
-
- // The magic code for version 1 export data.
- static const int v1_magic_len = 4;
- static const char v1_magic[v1_magic_len];
-
- // The length of the v1 checksum string.
- static const int v1_checksum_len = 20;
-
- // Register the builtin types.
- void
- register_builtin_types(Gogo*);
-
- // Export the identifiers in BINDINGS which are marked for export.
- // The exporting is done via a series of calls to THIS->STREAM_. If
- // is nothing to export, this->stream_->write will not be called.
- // PKGPATH is the package path.
- // PACKAGE_PRIORITY is the priority to use for this package.
- // IMPORT_INIT_FN is the name of the import initialization function
- // for this package; it will be empty if none is needed.
- // IMPORTED_INIT_FNS is the list of initialization functions for
- // imported packages.
- void
- export_globals(const std::string& package_name,
- const std::string& pkgpath,
- int package_priority,
- const std::map<std::string, Package*>& imports,
- const std::string& import_init_fn,
- const std::set<Import_init>& imported_init_fns,
- const Bindings* bindings);
-
- // Write a string to the export stream.
- void
- write_string(const std::string& s)
- { this->stream_->write_string(s); }
-
- // Write a nul terminated string to the export stream.
- void
- write_c_string(const char* s)
- { this->stream_->write_c_string(s); }
-
- // Write some bytes to the export stream.
- void
- write_bytes(const char* bytes, size_t length)
- { this->stream_->write_bytes(bytes, length); }
-
- // Write a name to the export stream. If NAME is empty, write "?".
- void
- write_name(const std::string& name);
-
- // Write out a type. This handles references back to previous
- // definitions.
- void
- write_type(const Type*);
-
- private:
- Export(const Export&);
- Export& operator=(const Export&);
-
- // Write out the imported packages.
- void
- write_imports(const std::map<std::string, Package*>& imports);
-
- // Write out the imported initialization functions.
- void
- write_imported_init_fns(const std::string& package_name, int priority,
- const std::string&, const std::set<Import_init>&);
-
- // Register one builtin type.
- void
- register_builtin_type(Gogo*, const char* name, Builtin_code);
-
- // Mapping from Type objects to a constant index.
- typedef Unordered_map(const Type*, int) Type_refs;
-
- // The stream to which we are writing data.
- Stream* stream_;
- // Type mappings.
- Type_refs type_refs_;
- // Index number of next type.
- int type_index_;
- // Packages we have written out.
- Unordered_set(const Package*) packages_;
-};
-
-// An export streamer which puts the export stream in a named section.
-
-class Stream_to_section : public Export::Stream
-{
- public:
- Stream_to_section();
-
- protected:
- void
- do_write(const char*, size_t);
-};
-
-#endif // !defined(GO_EXPORT_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/expressions.cc b/gcc-4.8.1/gcc/go/gofrontend/expressions.cc
deleted file mode 100644
index 9abd2247f..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/expressions.cc
+++ /dev/null
@@ -1,14467 +0,0 @@
-// expressions.cc -- Go frontend expression handling.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include <algorithm>
-
-#include "toplev.h"
-#include "intl.h"
-#include "tree.h"
-#include "gimple.h"
-#include "tree-iterator.h"
-#include "convert.h"
-#include "real.h"
-#include "realmpfr.h"
-
-#include "go-c.h"
-#include "gogo.h"
-#include "types.h"
-#include "export.h"
-#include "import.h"
-#include "statements.h"
-#include "lex.h"
-#include "runtime.h"
-#include "backend.h"
-#include "expressions.h"
-#include "ast-dump.h"
-
-// Class Expression.
-
-Expression::Expression(Expression_classification classification,
- Location location)
- : classification_(classification), location_(location)
-{
-}
-
-Expression::~Expression()
-{
-}
-
-// Traverse the expressions.
-
-int
-Expression::traverse(Expression** pexpr, Traverse* traverse)
-{
- Expression* expr = *pexpr;
- if ((traverse->traverse_mask() & Traverse::traverse_expressions) != 0)
- {
- int t = traverse->expression(pexpr);
- if (t == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- else if (t == TRAVERSE_SKIP_COMPONENTS)
- return TRAVERSE_CONTINUE;
- }
- return expr->do_traverse(traverse);
-}
-
-// Traverse subexpressions of this expression.
-
-int
-Expression::traverse_subexpressions(Traverse* traverse)
-{
- return this->do_traverse(traverse);
-}
-
-// Default implementation for do_traverse for child classes.
-
-int
-Expression::do_traverse(Traverse*)
-{
- return TRAVERSE_CONTINUE;
-}
-
-// This virtual function is called by the parser if the value of this
-// expression is being discarded. By default, we give an error.
-// Expressions with side effects override.
-
-bool
-Expression::do_discarding_value()
-{
- this->unused_value_error();
- return false;
-}
-
-// This virtual function is called to export expressions. This will
-// only be used by expressions which may be constant.
-
-void
-Expression::do_export(Export*) const
-{
- go_unreachable();
-}
-
-// Give an error saying that the value of the expression is not used.
-
-void
-Expression::unused_value_error()
-{
- this->report_error(_("value computed is not used"));
-}
-
-// Note that this expression is an error. This is called by children
-// when they discover an error.
-
-void
-Expression::set_is_error()
-{
- this->classification_ = EXPRESSION_ERROR;
-}
-
-// For children to call to report an error conveniently.
-
-void
-Expression::report_error(const char* msg)
-{
- error_at(this->location_, "%s", msg);
- this->set_is_error();
-}
-
-// Set types of variables and constants. This is implemented by the
-// child class.
-
-void
-Expression::determine_type(const Type_context* context)
-{
- this->do_determine_type(context);
-}
-
-// Set types when there is no context.
-
-void
-Expression::determine_type_no_context()
-{
- Type_context context;
- this->do_determine_type(&context);
-}
-
-// Return a tree handling any conversions which must be done during
-// assignment.
-
-tree
-Expression::convert_for_assignment(Translate_context* context, Type* lhs_type,
- Type* rhs_type, tree rhs_tree,
- Location location)
-{
- if (lhs_type->is_error() || rhs_type->is_error())
- return error_mark_node;
-
- if (rhs_tree == error_mark_node || TREE_TYPE(rhs_tree) == error_mark_node)
- return error_mark_node;
-
- Gogo* gogo = context->gogo();
-
- tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
- if (lhs_type_tree == error_mark_node)
- return error_mark_node;
-
- if (lhs_type->forwarded() != rhs_type->forwarded()
- && lhs_type->interface_type() != NULL)
- {
- if (rhs_type->interface_type() == NULL)
- return Expression::convert_type_to_interface(context, lhs_type,
- rhs_type, rhs_tree,
- location);
- else
- return Expression::convert_interface_to_interface(context, lhs_type,
- rhs_type, rhs_tree,
- false, location);
- }
- else if (lhs_type->forwarded() != rhs_type->forwarded()
- && rhs_type->interface_type() != NULL)
- return Expression::convert_interface_to_type(context, lhs_type, rhs_type,
- rhs_tree, location);
- else if (lhs_type->is_slice_type() && rhs_type->is_nil_type())
- {
- // Assigning nil to an open array.
- go_assert(TREE_CODE(lhs_type_tree) == RECORD_TYPE);
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 3);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(lhs_type_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- "__values") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- "__count") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), integer_zero_node);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- "__capacity") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), integer_zero_node);
-
- tree val = build_constructor(lhs_type_tree, init);
- TREE_CONSTANT(val) = 1;
-
- return val;
- }
- else if (rhs_type->is_nil_type())
- {
- // The left hand side should be a pointer type at the tree
- // level.
- go_assert(POINTER_TYPE_P(lhs_type_tree));
- return fold_convert(lhs_type_tree, null_pointer_node);
- }
- else if (lhs_type_tree == TREE_TYPE(rhs_tree))
- {
- // No conversion is needed.
- return rhs_tree;
- }
- else if (POINTER_TYPE_P(lhs_type_tree)
- || INTEGRAL_TYPE_P(lhs_type_tree)
- || SCALAR_FLOAT_TYPE_P(lhs_type_tree)
- || COMPLEX_FLOAT_TYPE_P(lhs_type_tree))
- return fold_convert_loc(location.gcc_location(), lhs_type_tree, rhs_tree);
- else if ((TREE_CODE(lhs_type_tree) == RECORD_TYPE
- && TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE)
- || (TREE_CODE(lhs_type_tree) == ARRAY_TYPE
- && TREE_CODE(TREE_TYPE(rhs_tree)) == ARRAY_TYPE))
- {
- // Avoid confusion from zero sized variables which may be
- // represented as non-zero-sized.
- if (int_size_in_bytes(lhs_type_tree) == 0
- || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0)
- return rhs_tree;
-
- // This conversion must be permitted by Go, or we wouldn't have
- // gotten here.
- go_assert(int_size_in_bytes(lhs_type_tree)
- == int_size_in_bytes(TREE_TYPE(rhs_tree)));
- return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR,
- lhs_type_tree, rhs_tree);
- }
- else
- {
- go_assert(useless_type_conversion_p(lhs_type_tree, TREE_TYPE(rhs_tree)));
- return rhs_tree;
- }
-}
-
-// Return a tree for a conversion from a non-interface type to an
-// interface type.
-
-tree
-Expression::convert_type_to_interface(Translate_context* context,
- Type* lhs_type, Type* rhs_type,
- tree rhs_tree, Location location)
-{
- Gogo* gogo = context->gogo();
- Interface_type* lhs_interface_type = lhs_type->interface_type();
- bool lhs_is_empty = lhs_interface_type->is_empty();
-
- // Since RHS_TYPE is a static type, we can create the interface
- // method table at compile time.
-
- // When setting an interface to nil, we just set both fields to
- // NULL.
- if (rhs_type->is_nil_type())
- {
- Btype* lhs_btype = lhs_type->get_backend(gogo);
- return expr_to_tree(gogo->backend()->zero_expression(lhs_btype));
- }
-
- // This should have been checked already.
- go_assert(lhs_interface_type->implements_interface(rhs_type, NULL));
-
- tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
- if (lhs_type_tree == error_mark_node)
- return error_mark_node;
-
- // An interface is a tuple. If LHS_TYPE is an empty interface type,
- // then the first field is the type descriptor for RHS_TYPE.
- // Otherwise it is the interface method table for RHS_TYPE.
- tree first_field_value;
- if (lhs_is_empty)
- first_field_value = rhs_type->type_descriptor_pointer(gogo, location);
- else
- {
- // Build the interface method table for this interface and this
- // object type: a list of function pointers for each interface
- // method.
- Named_type* rhs_named_type = rhs_type->named_type();
- Struct_type* rhs_struct_type = rhs_type->struct_type();
- bool is_pointer = false;
- if (rhs_named_type == NULL && rhs_struct_type == NULL)
- {
- rhs_named_type = rhs_type->deref()->named_type();
- rhs_struct_type = rhs_type->deref()->struct_type();
- is_pointer = true;
- }
- tree method_table;
- if (rhs_named_type != NULL)
- method_table =
- rhs_named_type->interface_method_table(gogo, lhs_interface_type,
- is_pointer);
- else if (rhs_struct_type != NULL)
- method_table =
- rhs_struct_type->interface_method_table(gogo, lhs_interface_type,
- is_pointer);
- else
- method_table = null_pointer_node;
- first_field_value = fold_convert_loc(location.gcc_location(),
- const_ptr_type_node, method_table);
- }
- if (first_field_value == error_mark_node)
- return error_mark_node;
-
- // Start building a constructor for the value we will return.
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(lhs_type_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- (lhs_is_empty ? "__type_descriptor" : "__methods")) == 0);
- elt->index = field;
- elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
- first_field_value);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
- elt->index = field;
-
- if (rhs_type->points_to() != NULL)
- {
- // We are assigning a pointer to the interface; the interface
- // holds the pointer itself.
- elt->value = rhs_tree;
- return build_constructor(lhs_type_tree, init);
- }
-
- // We are assigning a non-pointer value to the interface; the
- // interface gets a copy of the value in the heap.
-
- tree object_size = TYPE_SIZE_UNIT(TREE_TYPE(rhs_tree));
-
- tree space = gogo->allocate_memory(rhs_type, object_size, location);
- space = fold_convert_loc(location.gcc_location(),
- build_pointer_type(TREE_TYPE(rhs_tree)), space);
- space = save_expr(space);
-
- tree ref = build_fold_indirect_ref_loc(location.gcc_location(), space);
- TREE_THIS_NOTRAP(ref) = 1;
- tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR,
- void_type_node, ref, rhs_tree);
-
- elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
- space);
-
- return build2(COMPOUND_EXPR, lhs_type_tree, set,
- build_constructor(lhs_type_tree, init));
-}
-
-// Return a tree for the type descriptor of RHS_TREE, which has
-// interface type RHS_TYPE. If RHS_TREE is nil the result will be
-// NULL.
-
-tree
-Expression::get_interface_type_descriptor(Translate_context*,
- Type* rhs_type, tree rhs_tree,
- Location location)
-{
- tree rhs_type_tree = TREE_TYPE(rhs_tree);
- go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
- tree rhs_field = TYPE_FIELDS(rhs_type_tree);
- tree v = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
- NULL_TREE);
- if (rhs_type->interface_type()->is_empty())
- {
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)),
- "__type_descriptor") == 0);
- return v;
- }
-
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__methods")
- == 0);
- go_assert(POINTER_TYPE_P(TREE_TYPE(v)));
- v = save_expr(v);
- tree v1 = build_fold_indirect_ref_loc(location.gcc_location(), v);
- go_assert(TREE_CODE(TREE_TYPE(v1)) == RECORD_TYPE);
- tree f = TYPE_FIELDS(TREE_TYPE(v1));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(f)), "__type_descriptor")
- == 0);
- v1 = build3(COMPONENT_REF, TREE_TYPE(f), v1, f, NULL_TREE);
-
- tree eq = fold_build2_loc(location.gcc_location(), EQ_EXPR, boolean_type_node,
- v, fold_convert_loc(location.gcc_location(),
- TREE_TYPE(v),
- null_pointer_node));
- tree n = fold_convert_loc(location.gcc_location(), TREE_TYPE(v1),
- null_pointer_node);
- return fold_build3_loc(location.gcc_location(), COND_EXPR, TREE_TYPE(v1),
- eq, n, v1);
-}
-
-// Return a tree for the conversion of an interface type to an
-// interface type.
-
-tree
-Expression::convert_interface_to_interface(Translate_context* context,
- Type *lhs_type, Type *rhs_type,
- tree rhs_tree, bool for_type_guard,
- Location location)
-{
- Gogo* gogo = context->gogo();
- Interface_type* lhs_interface_type = lhs_type->interface_type();
- bool lhs_is_empty = lhs_interface_type->is_empty();
-
- tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
- if (lhs_type_tree == error_mark_node)
- return error_mark_node;
-
- // In the general case this requires runtime examination of the type
- // method table to match it up with the interface methods.
-
- // FIXME: If all of the methods in the right hand side interface
- // also appear in the left hand side interface, then we don't need
- // to do a runtime check, although we still need to build a new
- // method table.
-
- // Get the type descriptor for the right hand side. This will be
- // NULL for a nil interface.
-
- if (!DECL_P(rhs_tree))
- rhs_tree = save_expr(rhs_tree);
-
- tree rhs_type_descriptor =
- Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
- location);
-
- // The result is going to be a two element constructor.
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc (init, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(lhs_type_tree);
- elt->index = field;
-
- if (for_type_guard)
- {
- // A type assertion fails when converting a nil interface.
- tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo,
- location);
- static tree assert_interface_decl;
- tree call = Gogo::call_builtin(&assert_interface_decl,
- location,
- "__go_assert_interface",
- 2,
- ptr_type_node,
- TREE_TYPE(lhs_type_descriptor),
- 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.gcc_location(), TREE_TYPE(field),
- call);
- }
- else if (lhs_is_empty)
- {
- // A convertion to an empty interface always succeeds, and the
- // first field is just the type descriptor of the object.
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- "__type_descriptor") == 0);
- elt->value = fold_convert_loc(location.gcc_location(),
- TREE_TYPE(field), rhs_type_descriptor);
- }
- else
- {
- // A conversion to a non-empty interface may fail, but unlike a
- // type assertion converting nil will always succeed.
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods")
- == 0);
- tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo,
- location);
- static tree convert_interface_decl;
- tree call = Gogo::call_builtin(&convert_interface_decl,
- location,
- "__go_convert_interface",
- 2,
- ptr_type_node,
- TREE_TYPE(lhs_type_descriptor),
- 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.gcc_location(), TREE_TYPE(field),
- call);
- }
-
- // The second field is simply the object pointer.
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
- elt->index = field;
-
- tree rhs_type_tree = TREE_TYPE(rhs_tree);
- go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
- tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0);
- elt->value = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
- NULL_TREE);
-
- return build_constructor(lhs_type_tree, init);
-}
-
-// Return a tree for the conversion of an interface type to a
-// non-interface type.
-
-tree
-Expression::convert_interface_to_type(Translate_context* context,
- Type *lhs_type, Type* rhs_type,
- tree rhs_tree, Location location)
-{
- Gogo* gogo = context->gogo();
- tree rhs_type_tree = TREE_TYPE(rhs_tree);
-
- tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
- if (lhs_type_tree == error_mark_node)
- return error_mark_node;
-
- // Call a function to check that the type is valid. The function
- // will panic with an appropriate runtime type error if the type is
- // not valid.
-
- tree lhs_type_descriptor = lhs_type->type_descriptor_pointer(gogo, location);
-
- if (!DECL_P(rhs_tree))
- rhs_tree = save_expr(rhs_tree);
-
- tree rhs_type_descriptor =
- Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
- location);
-
- tree rhs_inter_descriptor = rhs_type->type_descriptor_pointer(gogo,
- location);
-
- static tree check_interface_type_decl;
- tree call = Gogo::call_builtin(&check_interface_type_decl,
- location,
- "__go_check_interface_type",
- 3,
- void_type_node,
- TREE_TYPE(lhs_type_descriptor),
- lhs_type_descriptor,
- TREE_TYPE(rhs_type_descriptor),
- 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;
-
- // If the call succeeds, pull out the value.
- go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
- tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0);
- tree val = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
- NULL_TREE);
-
- // If the value is a pointer, then it is the value we want.
- // Otherwise it points to the value.
- if (lhs_type->points_to() == NULL)
- {
- val = fold_convert_loc(location.gcc_location(),
- build_pointer_type(lhs_type_tree), val);
- val = build_fold_indirect_ref_loc(location.gcc_location(), val);
- }
-
- return build2(COMPOUND_EXPR, lhs_type_tree, call,
- fold_convert_loc(location.gcc_location(), lhs_type_tree, val));
-}
-
-// Convert an expression to a tree. This is implemented by the child
-// class. Not that it is not in general safe to call this multiple
-// times for a single expression, but that we don't catch such errors.
-
-tree
-Expression::get_tree(Translate_context* context)
-{
- // The child may have marked this expression as having an error.
- if (this->classification_ == EXPRESSION_ERROR)
- return error_mark_node;
-
- return this->do_get_tree(context);
-}
-
-// Return a tree for VAL in TYPE.
-
-tree
-Expression::integer_constant_tree(mpz_t val, tree type)
-{
- if (type == error_mark_node)
- return error_mark_node;
- else if (TREE_CODE(type) == INTEGER_TYPE)
- return double_int_to_tree(type,
- mpz_get_double_int(type, val, true));
- else if (TREE_CODE(type) == REAL_TYPE)
- {
- mpfr_t fval;
- mpfr_init_set_z(fval, val, GMP_RNDN);
- tree ret = Expression::float_constant_tree(fval, type);
- mpfr_clear(fval);
- return ret;
- }
- else if (TREE_CODE(type) == COMPLEX_TYPE)
- {
- mpfr_t fval;
- mpfr_init_set_z(fval, val, GMP_RNDN);
- tree real = Expression::float_constant_tree(fval, TREE_TYPE(type));
- mpfr_clear(fval);
- tree imag = build_real_from_int_cst(TREE_TYPE(type),
- integer_zero_node);
- return build_complex(type, real, imag);
- }
- else
- go_unreachable();
-}
-
-// Return a tree for VAL in TYPE.
-
-tree
-Expression::float_constant_tree(mpfr_t val, tree type)
-{
- if (type == error_mark_node)
- return error_mark_node;
- else if (TREE_CODE(type) == INTEGER_TYPE)
- {
- mpz_t ival;
- mpz_init(ival);
- mpfr_get_z(ival, val, GMP_RNDN);
- tree ret = Expression::integer_constant_tree(ival, type);
- mpz_clear(ival);
- return ret;
- }
- else if (TREE_CODE(type) == REAL_TYPE)
- {
- REAL_VALUE_TYPE r1;
- real_from_mpfr(&r1, val, type, GMP_RNDN);
- REAL_VALUE_TYPE r2;
- real_convert(&r2, TYPE_MODE(type), &r1);
- return build_real(type, r2);
- }
- else if (TREE_CODE(type) == COMPLEX_TYPE)
- {
- REAL_VALUE_TYPE r1;
- real_from_mpfr(&r1, val, TREE_TYPE(type), GMP_RNDN);
- REAL_VALUE_TYPE r2;
- real_convert(&r2, TYPE_MODE(TREE_TYPE(type)), &r1);
- tree imag = build_real_from_int_cst(TREE_TYPE(type),
- integer_zero_node);
- return build_complex(type, build_real(TREE_TYPE(type), r2), imag);
- }
- else
- go_unreachable();
-}
-
-// Return a tree for REAL/IMAG in TYPE.
-
-tree
-Expression::complex_constant_tree(mpfr_t real, mpfr_t imag, tree type)
-{
- if (type == error_mark_node)
- return error_mark_node;
- else if (TREE_CODE(type) == INTEGER_TYPE || TREE_CODE(type) == REAL_TYPE)
- return Expression::float_constant_tree(real, type);
- else if (TREE_CODE(type) == COMPLEX_TYPE)
- {
- REAL_VALUE_TYPE r1;
- real_from_mpfr(&r1, real, TREE_TYPE(type), GMP_RNDN);
- REAL_VALUE_TYPE r2;
- real_convert(&r2, TYPE_MODE(TREE_TYPE(type)), &r1);
-
- REAL_VALUE_TYPE r3;
- real_from_mpfr(&r3, imag, TREE_TYPE(type), GMP_RNDN);
- REAL_VALUE_TYPE r4;
- real_convert(&r4, TYPE_MODE(TREE_TYPE(type)), &r3);
-
- return build_complex(type, build_real(TREE_TYPE(type), r2),
- build_real(TREE_TYPE(type), r4));
- }
- else
- go_unreachable();
-}
-
-// Return a tree which evaluates to true if VAL, of arbitrary integer
-// type, is negative or is more than the maximum value of BOUND_TYPE.
-// If SOFAR is not NULL, it is or'red into the result. The return
-// value may be NULL if SOFAR is NULL.
-
-tree
-Expression::check_bounds(tree val, tree bound_type, tree sofar,
- Location loc)
-{
- tree val_type = TREE_TYPE(val);
- tree ret = NULL_TREE;
-
- if (!TYPE_UNSIGNED(val_type))
- {
- ret = fold_build2_loc(loc.gcc_location(), LT_EXPR, boolean_type_node, val,
- build_int_cst(val_type, 0));
- if (ret == boolean_false_node)
- ret = NULL_TREE;
- }
-
- HOST_WIDE_INT val_type_size = int_size_in_bytes(val_type);
- HOST_WIDE_INT bound_type_size = int_size_in_bytes(bound_type);
- go_assert(val_type_size != -1 && bound_type_size != -1);
- if (val_type_size > bound_type_size
- || (val_type_size == bound_type_size
- && TYPE_UNSIGNED(val_type)
- && !TYPE_UNSIGNED(bound_type)))
- {
- tree max = TYPE_MAX_VALUE(bound_type);
- tree big = fold_build2_loc(loc.gcc_location(), GT_EXPR, boolean_type_node,
- val, fold_convert_loc(loc.gcc_location(),
- val_type, max));
- if (big == boolean_false_node)
- ;
- else if (ret == NULL_TREE)
- ret = big;
- else
- ret = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, ret, big);
- }
-
- if (ret == NULL_TREE)
- return sofar;
- else if (sofar == NULL_TREE)
- return ret;
- else
- return fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, boolean_type_node,
- sofar, ret);
-}
-
-void
-Expression::dump_expression(Ast_dump_context* ast_dump_context) const
-{
- this->do_dump_expression(ast_dump_context);
-}
-
-// Error expressions. This are used to avoid cascading errors.
-
-class Error_expression : public Expression
-{
- public:
- Error_expression(Location location)
- : Expression(EXPRESSION_ERROR, location)
- { }
-
- protected:
- bool
- do_is_constant() const
- { return true; }
-
- bool
- do_numeric_constant_value(Numeric_constant* nc) const
- {
- nc->set_unsigned_long(NULL, 0);
- return true;
- }
-
- bool
- do_discarding_value()
- { return true; }
-
- Type*
- do_type()
- { return Type::make_error_type(); }
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- { return this; }
-
- bool
- do_is_addressable() const
- { return true; }
-
- tree
- do_get_tree(Translate_context*)
- { return error_mark_node; }
-
- void
- do_dump_expression(Ast_dump_context*) const;
-};
-
-// Dump the ast representation for an error expression to a dump context.
-
-void
-Error_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << "_Error_" ;
-}
-
-Expression*
-Expression::make_error(Location location)
-{
- return new Error_expression(location);
-}
-
-// An expression which is really a type. This is used during parsing.
-// It is an error if these survive after lowering.
-
-class
-Type_expression : public Expression
-{
- public:
- Type_expression(Type* type, Location location)
- : Expression(EXPRESSION_TYPE, location),
- type_(type)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Type::traverse(this->type_, traverse); }
-
- Type*
- do_type()
- { return this->type_; }
-
- void
- do_determine_type(const Type_context*)
- { }
-
- void
- do_check_types(Gogo*)
- { this->report_error(_("invalid use of type")); }
-
- Expression*
- do_copy()
- { return this; }
-
- tree
- do_get_tree(Translate_context*)
- { go_unreachable(); }
-
- void do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type which we are representing as an expression.
- Type* type_;
-};
-
-void
-Type_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->dump_type(this->type_);
-}
-
-Expression*
-Expression::make_type(Type* type, Location location)
-{
- return new Type_expression(type, location);
-}
-
-// Class Parser_expression.
-
-Type*
-Parser_expression::do_type()
-{
- // We should never really ask for the type of a Parser_expression.
- // However, it can happen, at least when we have an invalid const
- // whose initializer refers to the const itself. In that case we
- // may ask for the type when lowering the const itself.
- go_assert(saw_errors());
- return Type::make_error_type();
-}
-
-// Class Var_expression.
-
-// Lower a variable expression. Here we just make sure that the
-// initialization expression of the variable has been lowered. This
-// ensures that we will be able to determine the type of the variable
-// if necessary.
-
-Expression*
-Var_expression::do_lower(Gogo* gogo, Named_object* function,
- Statement_inserter* inserter, int)
-{
- if (this->variable_->is_variable())
- {
- Variable* var = this->variable_->var_value();
- // This is either a local variable or a global variable. A
- // reference to a variable which is local to an enclosing
- // function will be a reference to a field in a closure.
- if (var->is_global())
- {
- function = NULL;
- inserter = NULL;
- }
- var->lower_init_expression(gogo, function, inserter);
- }
- return this;
-}
-
-// Return the type of a reference to a variable.
-
-Type*
-Var_expression::do_type()
-{
- if (this->variable_->is_variable())
- return this->variable_->var_value()->type();
- else if (this->variable_->is_result_variable())
- return this->variable_->result_var_value()->type();
- else
- go_unreachable();
-}
-
-// Determine the type of a reference to a variable.
-
-void
-Var_expression::do_determine_type(const Type_context*)
-{
- if (this->variable_->is_variable())
- this->variable_->var_value()->determine_type();
-}
-
-// Something takes the address of this variable. This means that we
-// may want to move the variable onto the heap.
-
-void
-Var_expression::do_address_taken(bool escapes)
-{
- if (!escapes)
- {
- if (this->variable_->is_variable())
- this->variable_->var_value()->set_non_escaping_address_taken();
- else if (this->variable_->is_result_variable())
- this->variable_->result_var_value()->set_non_escaping_address_taken();
- else
- go_unreachable();
- }
- else
- {
- if (this->variable_->is_variable())
- this->variable_->var_value()->set_address_taken();
- else if (this->variable_->is_result_variable())
- this->variable_->result_var_value()->set_address_taken();
- else
- go_unreachable();
- }
-}
-
-// Get the tree for a reference to a variable.
-
-tree
-Var_expression::do_get_tree(Translate_context* context)
-{
- Bvariable* bvar = this->variable_->get_backend_variable(context->gogo(),
- context->function());
- tree ret = var_to_tree(bvar);
- if (ret == error_mark_node)
- return error_mark_node;
- bool is_in_heap;
- if (this->variable_->is_variable())
- is_in_heap = this->variable_->var_value()->is_in_heap();
- else if (this->variable_->is_result_variable())
- is_in_heap = this->variable_->result_var_value()->is_in_heap();
- else
- go_unreachable();
- if (is_in_heap)
- {
- ret = build_fold_indirect_ref_loc(this->location().gcc_location(), ret);
- TREE_THIS_NOTRAP(ret) = 1;
- }
- return ret;
-}
-
-// Ast dump for variable expression.
-
-void
-Var_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << this->variable_->name() ;
-}
-
-// Make a reference to a variable in an expression.
-
-Expression*
-Expression::make_var_reference(Named_object* var, Location location)
-{
- if (var->is_sink())
- return Expression::make_sink(location);
-
- // FIXME: Creating a new object for each reference to a variable is
- // wasteful.
- return new Var_expression(var, location);
-}
-
-// Class Temporary_reference_expression.
-
-// The type.
-
-Type*
-Temporary_reference_expression::do_type()
-{
- return this->statement_->type();
-}
-
-// Called if something takes the address of this temporary variable.
-// We never have to move temporary variables to the heap, but we do
-// need to know that they must live in the stack rather than in a
-// register.
-
-void
-Temporary_reference_expression::do_address_taken(bool)
-{
- this->statement_->set_is_address_taken();
-}
-
-// Get a tree referring to the variable.
-
-tree
-Temporary_reference_expression::do_get_tree(Translate_context* context)
-{
- Bvariable* bvar = this->statement_->get_backend_variable(context);
-
- // The gcc backend can't represent the same set of recursive types
- // that the Go frontend can. In some cases this means that a
- // temporary variable won't have the right backend type. Correct
- // that here by adding a type cast. We need to use base() to push
- // the circularity down one level.
- tree ret = var_to_tree(bvar);
- if (!this->is_lvalue_
- && POINTER_TYPE_P(TREE_TYPE(ret))
- && VOID_TYPE_P(TREE_TYPE(TREE_TYPE(ret))))
- {
- Btype* type_btype = this->type()->base()->get_backend(context->gogo());
- tree type_tree = type_to_tree(type_btype);
- ret = fold_convert_loc(this->location().gcc_location(), type_tree, ret);
- }
- return ret;
-}
-
-// Ast dump for temporary reference.
-
-void
-Temporary_reference_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->dump_temp_variable_name(this->statement_);
-}
-
-// Make a reference to a temporary variable.
-
-Temporary_reference_expression*
-Expression::make_temporary_reference(Temporary_statement* statement,
- Location location)
-{
- return new Temporary_reference_expression(statement, location);
-}
-
-// Class Set_and_use_temporary_expression.
-
-// Return the type.
-
-Type*
-Set_and_use_temporary_expression::do_type()
-{
- return this->statement_->type();
-}
-
-// Take the address.
-
-void
-Set_and_use_temporary_expression::do_address_taken(bool)
-{
- this->statement_->set_is_address_taken();
-}
-
-// Return the backend representation.
-
-tree
-Set_and_use_temporary_expression::do_get_tree(Translate_context* context)
-{
- Bvariable* bvar = this->statement_->get_backend_variable(context);
- tree var_tree = var_to_tree(bvar);
- tree expr_tree = this->expr_->get_tree(context);
- if (var_tree == error_mark_node || expr_tree == error_mark_node)
- return error_mark_node;
- Location loc = this->location();
- return build2_loc(loc.gcc_location(), COMPOUND_EXPR, TREE_TYPE(var_tree),
- build2_loc(loc.gcc_location(), MODIFY_EXPR, void_type_node,
- var_tree, expr_tree),
- var_tree);
-}
-
-// Dump.
-
-void
-Set_and_use_temporary_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << '(';
- ast_dump_context->dump_temp_variable_name(this->statement_);
- ast_dump_context->ostream() << " = ";
- this->expr_->dump_expression(ast_dump_context);
- ast_dump_context->ostream() << ')';
-}
-
-// Make a set-and-use temporary.
-
-Set_and_use_temporary_expression*
-Expression::make_set_and_use_temporary(Temporary_statement* statement,
- Expression* expr, Location location)
-{
- return new Set_and_use_temporary_expression(statement, expr, location);
-}
-
-// A sink expression--a use of the blank identifier _.
-
-class Sink_expression : public Expression
-{
- public:
- Sink_expression(Location location)
- : Expression(EXPRESSION_SINK, location),
- type_(NULL), var_(NULL_TREE)
- { }
-
- protected:
- bool
- do_discarding_value()
- { return true; }
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- Expression*
- do_copy()
- { return new Sink_expression(this->location()); }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type of this sink variable.
- Type* type_;
- // The temporary variable we generate.
- tree var_;
-};
-
-// Return the type of a sink expression.
-
-Type*
-Sink_expression::do_type()
-{
- if (this->type_ == NULL)
- return Type::make_sink_type();
- return this->type_;
-}
-
-// Determine the type of a sink expression.
-
-void
-Sink_expression::do_determine_type(const Type_context* context)
-{
- if (context->type != NULL)
- this->type_ = context->type;
-}
-
-// Return a temporary variable for a sink expression. This will
-// presumably be a write-only variable which the middle-end will drop.
-
-tree
-Sink_expression::do_get_tree(Translate_context* context)
-{
- if (this->var_ == NULL_TREE)
- {
- go_assert(this->type_ != NULL && !this->type_->is_sink_type());
- Btype* bt = this->type_->get_backend(context->gogo());
- this->var_ = create_tmp_var(type_to_tree(bt), "blank");
- }
- return this->var_;
-}
-
-// Ast dump for sink expression.
-
-void
-Sink_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << "_" ;
-}
-
-// Make a sink expression.
-
-Expression*
-Expression::make_sink(Location location)
-{
- return new Sink_expression(location);
-}
-
-// Class Func_expression.
-
-// FIXME: Can a function expression appear in a constant expression?
-// The value is unchanging. Initializing a constant to the address of
-// a function seems like it could work, though there might be little
-// point to it.
-
-// Traversal.
-
-int
-Func_expression::do_traverse(Traverse* traverse)
-{
- return (this->closure_ == NULL
- ? TRAVERSE_CONTINUE
- : Expression::traverse(&this->closure_, traverse));
-}
-
-// Return the type of a function expression.
-
-Type*
-Func_expression::do_type()
-{
- if (this->function_->is_function())
- return this->function_->func_value()->type();
- else if (this->function_->is_function_declaration())
- return this->function_->func_declaration_value()->type();
- else
- go_unreachable();
-}
-
-// Get the tree for a function expression without evaluating the
-// closure.
-
-tree
-Func_expression::get_tree_without_closure(Gogo* gogo)
-{
- Function_type* fntype;
- if (this->function_->is_function())
- fntype = this->function_->func_value()->type();
- else if (this->function_->is_function_declaration())
- fntype = this->function_->func_declaration_value()->type();
- else
- go_unreachable();
-
- // Builtin functions are handled specially by Call_expression. We
- // can't take their address.
- if (fntype->is_builtin())
- {
- error_at(this->location(),
- "invalid use of special builtin function %qs; must be called",
- this->function_->name().c_str());
- return error_mark_node;
- }
-
- Named_object* no = this->function_;
-
- tree id = no->get_id(gogo);
- if (id == error_mark_node)
- return error_mark_node;
-
- tree fndecl;
- if (no->is_function())
- fndecl = no->func_value()->get_or_make_decl(gogo, no, id);
- else if (no->is_function_declaration())
- fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no, id);
- else
- go_unreachable();
-
- if (fndecl == error_mark_node)
- return error_mark_node;
-
- return build_fold_addr_expr_loc(this->location().gcc_location(), fndecl);
-}
-
-// Get the tree for a function expression. This is used when we take
-// the address of a function rather than simply calling it. If the
-// function has a closure, we must use a trampoline.
-
-tree
-Func_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
-
- tree fnaddr = this->get_tree_without_closure(gogo);
- if (fnaddr == error_mark_node)
- return error_mark_node;
-
- go_assert(TREE_CODE(fnaddr) == ADDR_EXPR
- && TREE_CODE(TREE_OPERAND(fnaddr, 0)) == FUNCTION_DECL);
- TREE_ADDRESSABLE(TREE_OPERAND(fnaddr, 0)) = 1;
-
- // If there is no closure, that is all have to do.
- if (this->closure_ == NULL)
- return fnaddr;
-
- go_assert(this->function_->func_value()->enclosing() != NULL);
-
- // Get the value of the closure. This will be a pointer to space
- // allocated on the heap.
- tree closure_tree = this->closure_->get_tree(context);
- if (closure_tree == error_mark_node)
- return error_mark_node;
- go_assert(POINTER_TYPE_P(TREE_TYPE(closure_tree)));
-
- // Now we need to build some code on the heap. This code will load
- // the static chain pointer with the closure and then jump to the
- // body of the function. The normal gcc approach is to build the
- // code on the stack. Unfortunately we can not do that, as Go
- // permits us to return the function pointer.
-
- return gogo->make_trampoline(fnaddr, closure_tree, this->location());
-}
-
-// Ast dump for function.
-
-void
-Func_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << this->function_->name();
- if (this->closure_ != NULL)
- {
- ast_dump_context->ostream() << " {closure = ";
- this->closure_->dump_expression(ast_dump_context);
- ast_dump_context->ostream() << "}";
- }
-}
-
-// Make a reference to a function in an expression.
-
-Expression*
-Expression::make_func_reference(Named_object* function, Expression* closure,
- Location location)
-{
- return new Func_expression(function, closure, location);
-}
-
-// Class Unknown_expression.
-
-// Return the name of an unknown expression.
-
-const std::string&
-Unknown_expression::name() const
-{
- return this->named_object_->name();
-}
-
-// Lower a reference to an unknown name.
-
-Expression*
-Unknown_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
-{
- Location location = this->location();
- Named_object* no = this->named_object_;
- Named_object* real;
- if (!no->is_unknown())
- real = no;
- else
- {
- real = no->unknown_value()->real_named_object();
- if (real == NULL)
- {
- if (this->is_composite_literal_key_)
- return this;
- if (!this->no_error_message_)
- error_at(location, "reference to undefined name %qs",
- this->named_object_->message_name().c_str());
- return Expression::make_error(location);
- }
- }
- switch (real->classification())
- {
- case Named_object::NAMED_OBJECT_CONST:
- return Expression::make_const_reference(real, location);
- case Named_object::NAMED_OBJECT_TYPE:
- return Expression::make_type(real->type_value(), location);
- case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
- if (this->is_composite_literal_key_)
- return this;
- if (!this->no_error_message_)
- error_at(location, "reference to undefined type %qs",
- real->message_name().c_str());
- return Expression::make_error(location);
- case Named_object::NAMED_OBJECT_VAR:
- real->var_value()->set_is_used();
- return Expression::make_var_reference(real, location);
- case Named_object::NAMED_OBJECT_FUNC:
- case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
- return Expression::make_func_reference(real, NULL, location);
- case Named_object::NAMED_OBJECT_PACKAGE:
- if (this->is_composite_literal_key_)
- return this;
- if (!this->no_error_message_)
- error_at(location, "unexpected reference to package");
- return Expression::make_error(location);
- default:
- go_unreachable();
- }
-}
-
-// Dump the ast representation for an unknown expression to a dump context.
-
-void
-Unknown_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << "_Unknown_(" << this->named_object_->name()
- << ")";
-}
-
-// Make a reference to an unknown name.
-
-Unknown_expression*
-Expression::make_unknown_reference(Named_object* no, Location location)
-{
- return new Unknown_expression(no, location);
-}
-
-// A boolean expression.
-
-class Boolean_expression : public Expression
-{
- public:
- Boolean_expression(bool val, Location location)
- : Expression(EXPRESSION_BOOLEAN, location),
- val_(val), type_(NULL)
- { }
-
- static Expression*
- do_import(Import*);
-
- protected:
- bool
- do_is_constant() const
- { return true; }
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- Expression*
- do_copy()
- { return this; }
-
- tree
- do_get_tree(Translate_context*)
- { return this->val_ ? boolean_true_node : boolean_false_node; }
-
- void
- do_export(Export* exp) const
- { exp->write_c_string(this->val_ ? "true" : "false"); }
-
- void
- do_dump_expression(Ast_dump_context* ast_dump_context) const
- { ast_dump_context->ostream() << (this->val_ ? "true" : "false"); }
-
- private:
- // The constant.
- bool val_;
- // The type as determined by context.
- Type* type_;
-};
-
-// Get the type.
-
-Type*
-Boolean_expression::do_type()
-{
- if (this->type_ == NULL)
- this->type_ = Type::make_boolean_type();
- return this->type_;
-}
-
-// Set the type from the context.
-
-void
-Boolean_expression::do_determine_type(const Type_context* context)
-{
- if (this->type_ != NULL && !this->type_->is_abstract())
- ;
- else if (context->type != NULL && context->type->is_boolean_type())
- this->type_ = context->type;
- else if (!context->may_be_abstract)
- this->type_ = Type::lookup_bool_type();
-}
-
-// Import a boolean constant.
-
-Expression*
-Boolean_expression::do_import(Import* imp)
-{
- if (imp->peek_char() == 't')
- {
- imp->require_c_string("true");
- return Expression::make_boolean(true, imp->location());
- }
- else
- {
- imp->require_c_string("false");
- return Expression::make_boolean(false, imp->location());
- }
-}
-
-// Make a boolean expression.
-
-Expression*
-Expression::make_boolean(bool val, Location location)
-{
- return new Boolean_expression(val, location);
-}
-
-// Class String_expression.
-
-// Get the type.
-
-Type*
-String_expression::do_type()
-{
- if (this->type_ == NULL)
- this->type_ = Type::make_string_type();
- return this->type_;
-}
-
-// Set the type from the context.
-
-void
-String_expression::do_determine_type(const Type_context* context)
-{
- if (this->type_ != NULL && !this->type_->is_abstract())
- ;
- else if (context->type != NULL && context->type->is_string_type())
- this->type_ = context->type;
- else if (!context->may_be_abstract)
- this->type_ = Type::lookup_string_type();
-}
-
-// Build a string constant.
-
-tree
-String_expression::do_get_tree(Translate_context* context)
-{
- return context->gogo()->go_string_constant_tree(this->val_);
-}
-
- // Write string literal to string dump.
-
-void
-String_expression::export_string(String_dump* exp,
- const String_expression* str)
-{
- std::string s;
- s.reserve(str->val_.length() * 4 + 2);
- s += '"';
- for (std::string::const_iterator p = str->val_.begin();
- p != str->val_.end();
- ++p)
- {
- if (*p == '\\' || *p == '"')
- {
- s += '\\';
- s += *p;
- }
- else if (*p >= 0x20 && *p < 0x7f)
- s += *p;
- else if (*p == '\n')
- s += "\\n";
- else if (*p == '\t')
- s += "\\t";
- else
- {
- s += "\\x";
- unsigned char c = *p;
- unsigned int dig = c >> 4;
- s += dig < 10 ? '0' + dig : 'A' + dig - 10;
- dig = c & 0xf;
- s += dig < 10 ? '0' + dig : 'A' + dig - 10;
- }
- }
- s += '"';
- exp->write_string(s);
-}
-
-// Export a string expression.
-
-void
-String_expression::do_export(Export* exp) const
-{
- String_expression::export_string(exp, this);
-}
-
-// Import a string expression.
-
-Expression*
-String_expression::do_import(Import* imp)
-{
- imp->require_c_string("\"");
- std::string val;
- while (true)
- {
- int c = imp->get_char();
- if (c == '"' || c == -1)
- break;
- if (c != '\\')
- val += static_cast<char>(c);
- else
- {
- c = imp->get_char();
- if (c == '\\' || c == '"')
- val += static_cast<char>(c);
- else if (c == 'n')
- val += '\n';
- else if (c == 't')
- val += '\t';
- else if (c == 'x')
- {
- c = imp->get_char();
- unsigned int vh = c >= '0' && c <= '9' ? c - '0' : c - 'A' + 10;
- c = imp->get_char();
- unsigned int vl = c >= '0' && c <= '9' ? c - '0' : c - 'A' + 10;
- char v = (vh << 4) | vl;
- val += v;
- }
- else
- {
- error_at(imp->location(), "bad string constant");
- return Expression::make_error(imp->location());
- }
- }
- }
- return Expression::make_string(val, imp->location());
-}
-
-// Ast dump for string expression.
-
-void
-String_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- String_expression::export_string(ast_dump_context, this);
-}
-
-// Make a string expression.
-
-Expression*
-Expression::make_string(const std::string& val, Location location)
-{
- return new String_expression(val, location);
-}
-
-// Make an integer expression.
-
-class Integer_expression : public Expression
-{
- public:
- Integer_expression(const mpz_t* val, Type* type, bool is_character_constant,
- Location location)
- : Expression(EXPRESSION_INTEGER, location),
- type_(type), is_character_constant_(is_character_constant)
- { mpz_init_set(this->val_, *val); }
-
- static Expression*
- do_import(Import*);
-
- // Write VAL to string dump.
- static void
- export_integer(String_dump* exp, const mpz_t val);
-
- // Write VAL to dump context.
- static void
- dump_integer(Ast_dump_context* ast_dump_context, const mpz_t val);
-
- protected:
- bool
- do_is_constant() const
- { return true; }
-
- bool
- do_numeric_constant_value(Numeric_constant* nc) const;
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context* context);
-
- void
- do_check_types(Gogo*);
-
- tree
- do_get_tree(Translate_context*);
-
- Expression*
- do_copy()
- {
- if (this->is_character_constant_)
- return Expression::make_character(&this->val_, this->type_,
- this->location());
- else
- return Expression::make_integer(&this->val_, this->type_,
- this->location());
- }
-
- void
- do_export(Export*) const;
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The integer value.
- mpz_t val_;
- // The type so far.
- Type* type_;
- // Whether this is a character constant.
- bool is_character_constant_;
-};
-
-// Return a numeric constant for this expression. We have to mark
-// this as a character when appropriate.
-
-bool
-Integer_expression::do_numeric_constant_value(Numeric_constant* nc) const
-{
- if (this->is_character_constant_)
- nc->set_rune(this->type_, this->val_);
- else
- nc->set_int(this->type_, this->val_);
- return true;
-}
-
-// Return the current type. If we haven't set the type yet, we return
-// an abstract integer type.
-
-Type*
-Integer_expression::do_type()
-{
- if (this->type_ == NULL)
- {
- if (this->is_character_constant_)
- this->type_ = Type::make_abstract_character_type();
- else
- this->type_ = Type::make_abstract_integer_type();
- }
- return this->type_;
-}
-
-// Set the type of the integer value. Here we may switch from an
-// abstract type to a real type.
-
-void
-Integer_expression::do_determine_type(const Type_context* context)
-{
- if (this->type_ != NULL && !this->type_->is_abstract())
- ;
- else if (context->type != NULL && context->type->is_numeric_type())
- this->type_ = context->type;
- else if (!context->may_be_abstract)
- {
- if (this->is_character_constant_)
- this->type_ = Type::lookup_integer_type("int32");
- else
- this->type_ = Type::lookup_integer_type("int");
- }
-}
-
-// Check the type of an integer constant.
-
-void
-Integer_expression::do_check_types(Gogo*)
-{
- Type* type = this->type_;
- if (type == NULL)
- return;
- Numeric_constant nc;
- if (this->is_character_constant_)
- nc.set_rune(NULL, this->val_);
- else
- nc.set_int(NULL, this->val_);
- if (!nc.set_type(type, true, this->location()))
- this->set_is_error();
-}
-
-// Get a tree for an integer constant.
-
-tree
-Integer_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
- tree type;
- if (this->type_ != NULL && !this->type_->is_abstract())
- type = type_to_tree(this->type_->get_backend(gogo));
- else if (this->type_ != NULL && this->type_->float_type() != NULL)
- {
- // We are converting to an abstract floating point type.
- Type* ftype = Type::lookup_float_type("float64");
- type = type_to_tree(ftype->get_backend(gogo));
- }
- else if (this->type_ != NULL && this->type_->complex_type() != NULL)
- {
- // We are converting to an abstract complex type.
- Type* ctype = Type::lookup_complex_type("complex128");
- type = type_to_tree(ctype->get_backend(gogo));
- }
- else
- {
- // If we still have an abstract type here, then this is being
- // used in a constant expression which didn't get reduced for
- // some reason. Use a type which will fit the value. We use <,
- // not <=, because we need an extra bit for the sign bit.
- int bits = mpz_sizeinbase(this->val_, 2);
- Type* int_type = Type::lookup_integer_type("int");
- if (bits < int_type->integer_type()->bits())
- type = type_to_tree(int_type->get_backend(gogo));
- else if (bits < 64)
- {
- Type* t = Type::lookup_integer_type("int64");
- type = type_to_tree(t->get_backend(gogo));
- }
- else
- type = long_long_integer_type_node;
- }
- return Expression::integer_constant_tree(this->val_, type);
-}
-
-// Write VAL to export data.
-
-void
-Integer_expression::export_integer(String_dump* exp, const mpz_t val)
-{
- char* s = mpz_get_str(NULL, 10, val);
- exp->write_c_string(s);
- free(s);
-}
-
-// Export an integer in a constant expression.
-
-void
-Integer_expression::do_export(Export* exp) const
-{
- Integer_expression::export_integer(exp, this->val_);
- if (this->is_character_constant_)
- exp->write_c_string("'");
- // A trailing space lets us reliably identify the end of the number.
- exp->write_c_string(" ");
-}
-
-// Import an integer, floating point, or complex value. This handles
-// all these types because they all start with digits.
-
-Expression*
-Integer_expression::do_import(Import* imp)
-{
- std::string num = imp->read_identifier();
- imp->require_c_string(" ");
- if (!num.empty() && num[num.length() - 1] == 'i')
- {
- mpfr_t real;
- size_t plus_pos = num.find('+', 1);
- size_t minus_pos = num.find('-', 1);
- size_t pos;
- if (plus_pos == std::string::npos)
- pos = minus_pos;
- else if (minus_pos == std::string::npos)
- pos = plus_pos;
- else
- {
- error_at(imp->location(), "bad number in import data: %qs",
- num.c_str());
- return Expression::make_error(imp->location());
- }
- if (pos == std::string::npos)
- mpfr_set_ui(real, 0, GMP_RNDN);
- else
- {
- std::string real_str = num.substr(0, pos);
- if (mpfr_init_set_str(real, real_str.c_str(), 10, GMP_RNDN) != 0)
- {
- error_at(imp->location(), "bad number in import data: %qs",
- real_str.c_str());
- return Expression::make_error(imp->location());
- }
- }
-
- std::string imag_str;
- if (pos == std::string::npos)
- imag_str = num;
- else
- imag_str = num.substr(pos);
- imag_str = imag_str.substr(0, imag_str.size() - 1);
- mpfr_t imag;
- if (mpfr_init_set_str(imag, imag_str.c_str(), 10, GMP_RNDN) != 0)
- {
- error_at(imp->location(), "bad number in import data: %qs",
- imag_str.c_str());
- return Expression::make_error(imp->location());
- }
- Expression* ret = Expression::make_complex(&real, &imag, NULL,
- imp->location());
- mpfr_clear(real);
- mpfr_clear(imag);
- return ret;
- }
- else if (num.find('.') == std::string::npos
- && num.find('E') == std::string::npos)
- {
- bool is_character_constant = (!num.empty()
- && num[num.length() - 1] == '\'');
- if (is_character_constant)
- num = num.substr(0, num.length() - 1);
- mpz_t val;
- if (mpz_init_set_str(val, num.c_str(), 10) != 0)
- {
- error_at(imp->location(), "bad number in import data: %qs",
- num.c_str());
- return Expression::make_error(imp->location());
- }
- Expression* ret;
- if (is_character_constant)
- ret = Expression::make_character(&val, NULL, imp->location());
- else
- ret = Expression::make_integer(&val, NULL, imp->location());
- mpz_clear(val);
- return ret;
- }
- else
- {
- mpfr_t val;
- if (mpfr_init_set_str(val, num.c_str(), 10, GMP_RNDN) != 0)
- {
- error_at(imp->location(), "bad number in import data: %qs",
- num.c_str());
- return Expression::make_error(imp->location());
- }
- Expression* ret = Expression::make_float(&val, NULL, imp->location());
- mpfr_clear(val);
- return ret;
- }
-}
-// Ast dump for integer expression.
-
-void
-Integer_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- if (this->is_character_constant_)
- ast_dump_context->ostream() << '\'';
- Integer_expression::export_integer(ast_dump_context, this->val_);
- if (this->is_character_constant_)
- ast_dump_context->ostream() << '\'';
-}
-
-// Build a new integer value.
-
-Expression*
-Expression::make_integer(const mpz_t* val, Type* type, Location location)
-{
- return new Integer_expression(val, type, false, location);
-}
-
-// Build a new character constant value.
-
-Expression*
-Expression::make_character(const mpz_t* val, Type* type, Location location)
-{
- return new Integer_expression(val, type, true, location);
-}
-
-// Floats.
-
-class Float_expression : public Expression
-{
- public:
- Float_expression(const mpfr_t* val, Type* type, Location location)
- : Expression(EXPRESSION_FLOAT, location),
- type_(type)
- {
- mpfr_init_set(this->val_, *val, GMP_RNDN);
- }
-
- // Write VAL to export data.
- static void
- export_float(String_dump* exp, const mpfr_t val);
-
- // Write VAL to dump file.
- static void
- dump_float(Ast_dump_context* ast_dump_context, const mpfr_t val);
-
- protected:
- bool
- do_is_constant() const
- { return true; }
-
- bool
- do_numeric_constant_value(Numeric_constant* nc) const
- {
- nc->set_float(this->type_, this->val_);
- return true;
- }
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- { return Expression::make_float(&this->val_, this->type_,
- this->location()); }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_export(Export*) const;
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The floating point value.
- mpfr_t val_;
- // The type so far.
- Type* type_;
-};
-
-// Return the current type. If we haven't set the type yet, we return
-// an abstract float type.
-
-Type*
-Float_expression::do_type()
-{
- if (this->type_ == NULL)
- this->type_ = Type::make_abstract_float_type();
- return this->type_;
-}
-
-// Set the type of the float value. Here we may switch from an
-// abstract type to a real type.
-
-void
-Float_expression::do_determine_type(const Type_context* context)
-{
- if (this->type_ != NULL && !this->type_->is_abstract())
- ;
- else if (context->type != NULL
- && (context->type->integer_type() != NULL
- || context->type->float_type() != NULL
- || context->type->complex_type() != NULL))
- this->type_ = context->type;
- else if (!context->may_be_abstract)
- this->type_ = Type::lookup_float_type("float64");
-}
-
-// Check the type of a float value.
-
-void
-Float_expression::do_check_types(Gogo*)
-{
- Type* type = this->type_;
- if (type == NULL)
- return;
- Numeric_constant nc;
- nc.set_float(NULL, this->val_);
- if (!nc.set_type(this->type_, true, this->location()))
- this->set_is_error();
-}
-
-// Get a tree for a float constant.
-
-tree
-Float_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
- tree type;
- if (this->type_ != NULL && !this->type_->is_abstract())
- type = type_to_tree(this->type_->get_backend(gogo));
- else if (this->type_ != NULL && this->type_->integer_type() != NULL)
- {
- // We have an abstract integer type. We just hope for the best.
- type = type_to_tree(Type::lookup_integer_type("int")->get_backend(gogo));
- }
- else
- {
- // If we still have an abstract type here, then this is being
- // used in a constant expression which didn't get reduced. We
- // just use float64 and hope for the best.
- Type* ft = Type::lookup_float_type("float64");
- type = type_to_tree(ft->get_backend(gogo));
- }
- return Expression::float_constant_tree(this->val_, type);
-}
-
-// Write a floating point number to a string dump.
-
-void
-Float_expression::export_float(String_dump *exp, const mpfr_t val)
-{
- mp_exp_t exponent;
- char* s = mpfr_get_str(NULL, &exponent, 10, 0, val, GMP_RNDN);
- if (*s == '-')
- exp->write_c_string("-");
- exp->write_c_string("0.");
- exp->write_c_string(*s == '-' ? s + 1 : s);
- mpfr_free_str(s);
- char buf[30];
- snprintf(buf, sizeof buf, "E%ld", exponent);
- exp->write_c_string(buf);
-}
-
-// Export a floating point number in a constant expression.
-
-void
-Float_expression::do_export(Export* exp) const
-{
- Float_expression::export_float(exp, this->val_);
- // A trailing space lets us reliably identify the end of the number.
- exp->write_c_string(" ");
-}
-
-// Dump a floating point number to the dump file.
-
-void
-Float_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- Float_expression::export_float(ast_dump_context, this->val_);
-}
-
-// Make a float expression.
-
-Expression*
-Expression::make_float(const mpfr_t* val, Type* type, Location location)
-{
- return new Float_expression(val, type, location);
-}
-
-// Complex numbers.
-
-class Complex_expression : public Expression
-{
- public:
- Complex_expression(const mpfr_t* real, const mpfr_t* imag, Type* type,
- Location location)
- : Expression(EXPRESSION_COMPLEX, location),
- type_(type)
- {
- mpfr_init_set(this->real_, *real, GMP_RNDN);
- mpfr_init_set(this->imag_, *imag, GMP_RNDN);
- }
-
- // Write REAL/IMAG to string dump.
- static void
- export_complex(String_dump* exp, const mpfr_t real, const mpfr_t val);
-
- // Write REAL/IMAG to dump context.
- static void
- dump_complex(Ast_dump_context* ast_dump_context,
- const mpfr_t real, const mpfr_t val);
-
- protected:
- bool
- do_is_constant() const
- { return true; }
-
- bool
- do_numeric_constant_value(Numeric_constant* nc) const
- {
- nc->set_complex(this->type_, this->real_, this->imag_);
- return true;
- }
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_complex(&this->real_, &this->imag_, this->type_,
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_export(Export*) const;
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The real part.
- mpfr_t real_;
- // The imaginary part;
- mpfr_t imag_;
- // The type if known.
- Type* type_;
-};
-
-// Return the current type. If we haven't set the type yet, we return
-// an abstract complex type.
-
-Type*
-Complex_expression::do_type()
-{
- if (this->type_ == NULL)
- this->type_ = Type::make_abstract_complex_type();
- return this->type_;
-}
-
-// Set the type of the complex value. Here we may switch from an
-// abstract type to a real type.
-
-void
-Complex_expression::do_determine_type(const Type_context* context)
-{
- if (this->type_ != NULL && !this->type_->is_abstract())
- ;
- else if (context->type != NULL
- && context->type->complex_type() != NULL)
- this->type_ = context->type;
- else if (!context->may_be_abstract)
- this->type_ = Type::lookup_complex_type("complex128");
-}
-
-// Check the type of a complex value.
-
-void
-Complex_expression::do_check_types(Gogo*)
-{
- Type* type = this->type_;
- if (type == NULL)
- return;
- Numeric_constant nc;
- nc.set_complex(NULL, this->real_, this->imag_);
- if (!nc.set_type(this->type_, true, this->location()))
- this->set_is_error();
-}
-
-// Get a tree for a complex constant.
-
-tree
-Complex_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
- tree type;
- if (this->type_ != NULL && !this->type_->is_abstract())
- type = type_to_tree(this->type_->get_backend(gogo));
- else
- {
- // If we still have an abstract type here, this this is being
- // used in a constant expression which didn't get reduced. We
- // just use complex128 and hope for the best.
- Type* ct = Type::lookup_complex_type("complex128");
- type = type_to_tree(ct->get_backend(gogo));
- }
- return Expression::complex_constant_tree(this->real_, this->imag_, type);
-}
-
-// Write REAL/IMAG to export data.
-
-void
-Complex_expression::export_complex(String_dump* exp, const mpfr_t real,
- const mpfr_t imag)
-{
- if (!mpfr_zero_p(real))
- {
- Float_expression::export_float(exp, real);
- if (mpfr_sgn(imag) > 0)
- exp->write_c_string("+");
- }
- Float_expression::export_float(exp, imag);
- exp->write_c_string("i");
-}
-
-// Export a complex number in a constant expression.
-
-void
-Complex_expression::do_export(Export* exp) const
-{
- Complex_expression::export_complex(exp, this->real_, this->imag_);
- // A trailing space lets us reliably identify the end of the number.
- exp->write_c_string(" ");
-}
-
-// Dump a complex expression to the dump file.
-
-void
-Complex_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- Complex_expression::export_complex(ast_dump_context,
- this->real_,
- this->imag_);
-}
-
-// Make a complex expression.
-
-Expression*
-Expression::make_complex(const mpfr_t* real, const mpfr_t* imag, Type* type,
- Location location)
-{
- 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
-{
- public:
- Const_expression(Named_object* constant, Location location)
- : Expression(EXPRESSION_CONST_REFERENCE, location),
- constant_(constant), type_(NULL), seen_(false)
- { }
-
- Named_object*
- named_object()
- { return this->constant_; }
-
- // Check that the initializer does not refer to the constant itself.
- void
- check_for_init_loop();
-
- protected:
- int
- do_traverse(Traverse*);
-
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- bool
- do_is_constant() const
- { return true; }
-
- bool
- do_numeric_constant_value(Numeric_constant* nc) const;
-
- bool
- do_string_constant_value(std::string* val) const;
-
- Type*
- do_type();
-
- // The type of a const is set by the declaration, not the use.
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- { return this; }
-
- tree
- do_get_tree(Translate_context* context);
-
- // When exporting a reference to a const as part of a const
- // expression, we export the value. We ignore the fact that it has
- // a name.
- void
- do_export(Export* exp) const
- { this->constant_->const_value()->expr()->export_expression(exp); }
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The constant.
- Named_object* constant_;
- // 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_;
-};
-
-// Traversal.
-
-int
-Const_expression::do_traverse(Traverse* traverse)
-{
- if (this->type_ != NULL)
- return Type::traverse(this->type_, traverse);
- return TRAVERSE_CONTINUE;
-}
-
-// Lower a constant expression. This is where we convert the
-// predeclared constant iota into an integer value.
-
-Expression*
-Const_expression::do_lower(Gogo* gogo, Named_object*,
- Statement_inserter*, int iota_value)
-{
- if (this->constant_->const_value()->expr()->classification()
- == EXPRESSION_IOTA)
- {
- if (iota_value == -1)
- {
- error_at(this->location(),
- "iota is only defined in const declarations");
- iota_value = 0;
- }
- mpz_t val;
- mpz_init_set_ui(val, static_cast<unsigned long>(iota_value));
- Expression* ret = Expression::make_integer(&val, NULL,
- this->location());
- mpz_clear(val);
- return ret;
- }
-
- // Make sure that the constant itself has been lowered.
- gogo->lower_constant(this->constant_);
-
- return this;
-}
-
-// Return a numeric constant value.
-
-bool
-Const_expression::do_numeric_constant_value(Numeric_constant* nc) const
-{
- if (this->seen_)
- return false;
-
- Expression* e = this->constant_->const_value()->expr();
-
- this->seen_ = true;
-
- bool r = e->numeric_constant_value(nc);
-
- this->seen_ = false;
-
- Type* ctype;
- if (this->type_ != NULL)
- ctype = this->type_;
- else
- ctype = this->constant_->const_value()->type();
- if (r && ctype != NULL)
- {
- if (!nc->set_type(ctype, false, this->location()))
- return false;
- }
-
- return r;
-}
-
-bool
-Const_expression::do_string_constant_value(std::string* val) const
-{
- if (this->seen_)
- return false;
-
- Expression* e = this->constant_->const_value()->expr();
-
- this->seen_ = true;
- bool ok = e->string_constant_value(val);
- this->seen_ = false;
-
- return ok;
-}
-
-// Return the type of the const reference.
-
-Type*
-Const_expression::do_type()
-{
- if (this->type_ != NULL)
- return this->type_;
-
- Named_constant* nc = this->constant_->const_value();
-
- if (this->seen_ || nc->lowering())
- {
- this->report_error(_("constant refers to itself"));
- this->type_ = Type::make_error_type();
- return this->type_;
- }
-
- this->seen_ = true;
-
- Type* ret = nc->type();
-
- if (ret != NULL)
- {
- this->seen_ = false;
- return ret;
- }
-
- // During parsing, a named constant may have a NULL type, but we
- // must not return a NULL type here.
- ret = nc->expr()->type();
-
- this->seen_ = false;
-
- return ret;
-}
-
-// Set the type of the const reference.
-
-void
-Const_expression::do_determine_type(const Type_context* context)
-{
- Type* ctype = this->constant_->const_value()->type();
- Type* cetype = (ctype != NULL
- ? ctype
- : this->constant_->const_value()->expr()->type());
- if (ctype != NULL && !ctype->is_abstract())
- ;
- else if (context->type != NULL
- && context->type->is_numeric_type()
- && cetype->is_numeric_type())
- this->type_ = context->type;
- else if (context->type != NULL
- && context->type->is_string_type()
- && cetype->is_string_type())
- this->type_ = context->type;
- else if (context->type != NULL
- && context->type->is_boolean_type()
- && cetype->is_boolean_type())
- this->type_ = context->type;
- else if (!context->may_be_abstract)
- {
- if (cetype->is_abstract())
- cetype = cetype->make_non_abstract_type();
- this->type_ = cetype;
- }
-}
-
-// Check for a loop in which the initializer of a constant refers to
-// the constant itself.
-
-void
-Const_expression::check_for_init_loop()
-{
- if (this->type_ != NULL && this->type_->is_error())
- return;
-
- if (this->seen_)
- {
- this->report_error(_("constant refers to itself"));
- this->type_ = Type::make_error_type();
- return;
- }
-
- Expression* init = this->constant_->const_value()->expr();
- Find_named_object find_named_object(this->constant_);
-
- this->seen_ = true;
- Expression::traverse(&init, &find_named_object);
- this->seen_ = false;
-
- if (find_named_object.found())
- {
- if (this->type_ == NULL || !this->type_->is_error())
- {
- this->report_error(_("constant refers to itself"));
- this->type_ = Type::make_error_type();
- }
- return;
- }
-}
-
-// Check types of a const reference.
-
-void
-Const_expression::do_check_types(Gogo*)
-{
- if (this->type_ != NULL && this->type_->is_error())
- return;
-
- this->check_for_init_loop();
-
- // Check that numeric constant fits in type.
- if (this->type_ != NULL && this->type_->is_numeric_type())
- {
- Numeric_constant nc;
- if (this->constant_->const_value()->expr()->numeric_constant_value(&nc))
- {
- if (!nc.set_type(this->type_, true, this->location()))
- this->set_is_error();
- }
- }
-}
-
-// Return a tree for the const reference.
-
-tree
-Const_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
- tree type_tree;
- if (this->type_ == NULL)
- type_tree = NULL_TREE;
- else
- {
- type_tree = type_to_tree(this->type_->get_backend(gogo));
- if (type_tree == error_mark_node)
- return error_mark_node;
- }
-
- // If the type has been set for this expression, but the underlying
- // object is an abstract int or float, we try to get the abstract
- // value. Otherwise we may lose something in the conversion.
- if (this->type_ != NULL
- && this->type_->is_numeric_type()
- && (this->constant_->const_value()->type() == NULL
- || this->constant_->const_value()->type()->is_abstract()))
- {
- Expression* expr = this->constant_->const_value()->expr();
- Numeric_constant nc;
- if (expr->numeric_constant_value(&nc)
- && nc.set_type(this->type_, false, this->location()))
- {
- Expression* e = nc.expression(this->location());
- return e->get_tree(context);
- }
- }
-
- tree const_tree = this->constant_->get_tree(gogo, context->function());
- if (this->type_ == NULL
- || const_tree == error_mark_node
- || TREE_TYPE(const_tree) == error_mark_node)
- return const_tree;
-
- tree ret;
- if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(const_tree)))
- ret = fold_convert(type_tree, const_tree);
- else if (TREE_CODE(type_tree) == INTEGER_TYPE)
- ret = fold(convert_to_integer(type_tree, const_tree));
- else if (TREE_CODE(type_tree) == REAL_TYPE)
- ret = fold(convert_to_real(type_tree, const_tree));
- else if (TREE_CODE(type_tree) == COMPLEX_TYPE)
- ret = fold(convert_to_complex(type_tree, const_tree));
- else
- go_unreachable();
- return ret;
-}
-
-// Dump ast representation for constant expression.
-
-void
-Const_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << this->constant_->name();
-}
-
-// Make a reference to a constant in an expression.
-
-Expression*
-Expression::make_const_reference(Named_object* constant,
- Location location)
-{
- 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:
- {
- Const_expression* ce = static_cast<Const_expression*>(*pexpr);
- if (ce->named_object() == this->no_)
- break;
-
- // We need to check a constant initializer explicitly, as
- // loops here will not be caught by the loop checking for
- // variable initializers.
- ce->check_for_init_loop();
-
- 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
-{
- public:
- Nil_expression(Location location)
- : Expression(EXPRESSION_NIL, location)
- { }
-
- static Expression*
- do_import(Import*);
-
- protected:
- bool
- do_is_constant() const
- { return true; }
-
- Type*
- do_type()
- { return Type::make_nil_type(); }
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- { return this; }
-
- tree
- do_get_tree(Translate_context*)
- { return null_pointer_node; }
-
- void
- do_export(Export* exp) const
- { exp->write_c_string("nil"); }
-
- void
- do_dump_expression(Ast_dump_context* ast_dump_context) const
- { ast_dump_context->ostream() << "nil"; }
-};
-
-// Import a nil expression.
-
-Expression*
-Nil_expression::do_import(Import* imp)
-{
- imp->require_c_string("nil");
- return Expression::make_nil(imp->location());
-}
-
-// Make a nil expression.
-
-Expression*
-Expression::make_nil(Location location)
-{
- return new Nil_expression(location);
-}
-
-// The value of the predeclared constant iota. This is little more
-// than a marker. This will be lowered to an integer in
-// Const_expression::do_lower, which is where we know the value that
-// it should have.
-
-class Iota_expression : public Parser_expression
-{
- public:
- Iota_expression(Location location)
- : Parser_expression(EXPRESSION_IOTA, location)
- { }
-
- protected:
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int)
- { go_unreachable(); }
-
- // There should only ever be one of these.
- Expression*
- do_copy()
- { go_unreachable(); }
-
- void
- do_dump_expression(Ast_dump_context* ast_dump_context) const
- { ast_dump_context->ostream() << "iota"; }
-};
-
-// Make an iota expression. This is only called for one case: the
-// value of the predeclared constant iota.
-
-Expression*
-Expression::make_iota()
-{
- static Iota_expression iota_expression(Linemap::unknown_location());
- return &iota_expression;
-}
-
-// A type conversion expression.
-
-class Type_conversion_expression : public Expression
-{
- public:
- Type_conversion_expression(Type* type, Expression* expr,
- Location location)
- : Expression(EXPRESSION_CONVERSION, location),
- type_(type), expr_(expr), may_convert_function_types_(false)
- { }
-
- // Return the type to which we are converting.
- Type*
- type() const
- { return this->type_; }
-
- // Return the expression which we are converting.
- Expression*
- expr() const
- { return this->expr_; }
-
- // Permit converting from one function type to another. This is
- // used internally for method expressions.
- void
- set_may_convert_function_types()
- {
- this->may_convert_function_types_ = true;
- }
-
- // Import a type conversion expression.
- static Expression*
- do_import(Import*);
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- bool
- do_is_constant() const
- { return this->expr_->is_constant(); }
-
- bool
- do_numeric_constant_value(Numeric_constant*) const;
-
- bool
- do_string_constant_value(std::string*) const;
-
- Type*
- do_type()
- { return this->type_; }
-
- void
- do_determine_type(const Type_context*)
- {
- Type_context subcontext(this->type_, false);
- this->expr_->determine_type(&subcontext);
- }
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return new Type_conversion_expression(this->type_, this->expr_->copy(),
- this->location());
- }
-
- tree
- do_get_tree(Translate_context* context);
-
- void
- do_export(Export*) const;
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type to convert to.
- Type* type_;
- // The expression to convert.
- Expression* expr_;
- // True if this is permitted to convert function types. This is
- // used internally for method expressions.
- bool may_convert_function_types_;
-};
-
-// Traversal.
-
-int
-Type_conversion_expression::do_traverse(Traverse* traverse)
-{
- if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT
- || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Convert to a constant at lowering time.
-
-Expression*
-Type_conversion_expression::do_lower(Gogo*, Named_object*,
- Statement_inserter*, int)
-{
- Type* type = this->type_;
- Expression* val = this->expr_;
- Location location = this->location();
-
- if (type->is_numeric_type())
- {
- Numeric_constant nc;
- if (val->numeric_constant_value(&nc))
- {
- if (!nc.set_type(type, true, location))
- return Expression::make_error(location);
- return nc.expression(location);
- }
- }
-
- if (type->is_slice_type())
- {
- Type* element_type = type->array_type()->element_type()->forwarded();
- bool is_byte = (element_type->integer_type() != NULL
- && element_type->integer_type()->is_byte());
- bool is_rune = (element_type->integer_type() != NULL
- && element_type->integer_type()->is_rune());
- if (is_byte || is_rune)
- {
- std::string s;
- if (val->string_constant_value(&s))
- {
- Expression_list* vals = new Expression_list();
- if (is_byte)
- {
- for (std::string::const_iterator p = s.begin();
- p != s.end();
- p++)
- {
- mpz_t val;
- mpz_init_set_ui(val, static_cast<unsigned char>(*p));
- Expression* v = Expression::make_integer(&val,
- element_type,
- location);
- vals->push_back(v);
- mpz_clear(val);
- }
- }
- else
- {
- const char *p = s.data();
- const char *pend = s.data() + s.length();
- while (p < pend)
- {
- unsigned int c;
- int adv = Lex::fetch_char(p, &c);
- if (adv == 0)
- {
- warning_at(this->location(), 0,
- "invalid UTF-8 encoding");
- adv = 1;
- }
- p += adv;
- mpz_t val;
- mpz_init_set_ui(val, c);
- Expression* v = Expression::make_integer(&val,
- element_type,
- location);
- vals->push_back(v);
- mpz_clear(val);
- }
- }
-
- return Expression::make_slice_composite_literal(type, vals,
- location);
- }
- }
- }
-
- return this;
-}
-
-// Return the constant numeric value if there is one.
-
-bool
-Type_conversion_expression::do_numeric_constant_value(
- Numeric_constant* nc) const
-{
- if (!this->type_->is_numeric_type())
- return false;
- if (!this->expr_->numeric_constant_value(nc))
- return false;
- return nc->set_type(this->type_, false, this->location());
-}
-
-// Return the constant string value if there is one.
-
-bool
-Type_conversion_expression::do_string_constant_value(std::string* val) const
-{
- if (this->type_->is_string_type()
- && this->expr_->type()->integer_type() != NULL)
- {
- Numeric_constant nc;
- if (this->expr_->numeric_constant_value(&nc))
- {
- unsigned long ival;
- if (nc.to_unsigned_long(&ival) == Numeric_constant::NC_UL_VALID)
- {
- val->clear();
- Lex::append_char(ival, true, val, this->location());
- return true;
- }
- }
- }
-
- // FIXME: Could handle conversion from const []int here.
-
- return false;
-}
-
-// Check that types are convertible.
-
-void
-Type_conversion_expression::do_check_types(Gogo*)
-{
- Type* type = this->type_;
- Type* expr_type = this->expr_->type();
- std::string reason;
-
- if (type->is_error() || expr_type->is_error())
- {
- this->set_is_error();
- return;
- }
-
- if (this->may_convert_function_types_
- && type->function_type() != NULL
- && expr_type->function_type() != NULL)
- return;
-
- if (Type::are_convertible(type, expr_type, &reason))
- return;
-
- error_at(this->location(), "%s", reason.c_str());
- this->set_is_error();
-}
-
-// Get a tree for a type conversion.
-
-tree
-Type_conversion_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
- tree type_tree = type_to_tree(this->type_->get_backend(gogo));
- tree expr_tree = this->expr_->get_tree(context);
-
- if (type_tree == error_mark_node
- || expr_tree == error_mark_node
- || TREE_TYPE(expr_tree) == error_mark_node)
- return error_mark_node;
-
- if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(expr_tree)))
- return fold_convert(type_tree, expr_tree);
-
- Type* type = this->type_;
- Type* expr_type = this->expr_->type();
- tree ret;
- if (type->interface_type() != NULL || expr_type->interface_type() != NULL)
- ret = Expression::convert_for_assignment(context, type, expr_type,
- expr_tree, this->location());
- else if (type->integer_type() != NULL)
- {
- if (expr_type->integer_type() != NULL
- || expr_type->float_type() != NULL
- || expr_type->is_unsafe_pointer_type())
- ret = fold(convert_to_integer(type_tree, expr_tree));
- else
- go_unreachable();
- }
- else if (type->float_type() != NULL)
- {
- if (expr_type->integer_type() != NULL
- || expr_type->float_type() != NULL)
- ret = fold(convert_to_real(type_tree, expr_tree));
- else
- go_unreachable();
- }
- else if (type->complex_type() != NULL)
- {
- if (expr_type->complex_type() != NULL)
- ret = fold(convert_to_complex(type_tree, expr_tree));
- else
- go_unreachable();
- }
- else if (type->is_string_type()
- && expr_type->integer_type() != NULL)
- {
- Type* int_type = Type::lookup_integer_type("int");
- tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
-
- expr_tree = fold_convert(int_type_tree, expr_tree);
- if (host_integerp(expr_tree, 0))
- {
- HOST_WIDE_INT intval = tree_low_cst(expr_tree, 0);
- std::string s;
- Lex::append_char(intval, true, &s, this->location());
- Expression* se = Expression::make_string(s, this->location());
- return se->get_tree(context);
- }
-
- static tree int_to_string_fndecl;
- ret = Gogo::call_builtin(&int_to_string_fndecl,
- this->location(),
- "__go_int_to_string",
- 1,
- type_tree,
- int_type_tree,
- expr_tree);
- }
- else if (type->is_string_type() && expr_type->is_slice_type())
- {
- if (!DECL_P(expr_tree))
- expr_tree = save_expr(expr_tree);
-
- Type* int_type = Type::lookup_integer_type("int");
- tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
-
- Array_type* a = expr_type->array_type();
- Type* e = a->element_type()->forwarded();
- go_assert(e->integer_type() != NULL);
- tree valptr = fold_convert(const_ptr_type_node,
- a->value_pointer_tree(gogo, expr_tree));
- tree len = a->length_tree(gogo, expr_tree);
- len = fold_convert_loc(this->location().gcc_location(), int_type_tree,
- len);
- if (e->integer_type()->is_byte())
- {
- static tree byte_array_to_string_fndecl;
- ret = Gogo::call_builtin(&byte_array_to_string_fndecl,
- this->location(),
- "__go_byte_array_to_string",
- 2,
- type_tree,
- const_ptr_type_node,
- valptr,
- int_type_tree,
- len);
- }
- else
- {
- go_assert(e->integer_type()->is_rune());
- static tree int_array_to_string_fndecl;
- ret = Gogo::call_builtin(&int_array_to_string_fndecl,
- this->location(),
- "__go_int_array_to_string",
- 2,
- type_tree,
- const_ptr_type_node,
- valptr,
- int_type_tree,
- len);
- }
- }
- else if (type->is_slice_type() && expr_type->is_string_type())
- {
- Type* e = type->array_type()->element_type()->forwarded();
- go_assert(e->integer_type() != NULL);
- if (e->integer_type()->is_byte())
- {
- tree string_to_byte_array_fndecl = NULL_TREE;
- ret = Gogo::call_builtin(&string_to_byte_array_fndecl,
- this->location(),
- "__go_string_to_byte_array",
- 1,
- type_tree,
- TREE_TYPE(expr_tree),
- expr_tree);
- }
- else
- {
- go_assert(e->integer_type()->is_rune());
- tree string_to_int_array_fndecl = NULL_TREE;
- ret = Gogo::call_builtin(&string_to_int_array_fndecl,
- this->location(),
- "__go_string_to_int_array",
- 1,
- type_tree,
- TREE_TYPE(expr_tree),
- expr_tree);
- }
- }
- else if ((type->is_unsafe_pointer_type()
- && expr_type->points_to() != NULL)
- || (expr_type->is_unsafe_pointer_type()
- && type->points_to() != NULL))
- ret = fold_convert(type_tree, expr_tree);
- else if (type->is_unsafe_pointer_type()
- && expr_type->integer_type() != NULL)
- ret = convert_to_pointer(type_tree, expr_tree);
- else if (this->may_convert_function_types_
- && type->function_type() != NULL
- && expr_type->function_type() != NULL)
- ret = fold_convert_loc(this->location().gcc_location(), type_tree,
- expr_tree);
- else
- ret = Expression::convert_for_assignment(context, type, expr_type,
- expr_tree, this->location());
-
- return ret;
-}
-
-// Output a type conversion in a constant expression.
-
-void
-Type_conversion_expression::do_export(Export* exp) const
-{
- exp->write_c_string("convert(");
- exp->write_type(this->type_);
- exp->write_c_string(", ");
- this->expr_->export_expression(exp);
- exp->write_c_string(")");
-}
-
-// Import a type conversion or a struct construction.
-
-Expression*
-Type_conversion_expression::do_import(Import* imp)
-{
- imp->require_c_string("convert(");
- Type* type = imp->read_type();
- imp->require_c_string(", ");
- Expression* val = Expression::import_expression(imp);
- imp->require_c_string(")");
- return Expression::make_cast(type, val, imp->location());
-}
-
-// Dump ast representation for a type conversion expression.
-
-void
-Type_conversion_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << "(";
- ast_dump_context->dump_expression(this->expr_);
- ast_dump_context->ostream() << ") ";
-}
-
-// Make a type cast expression.
-
-Expression*
-Expression::make_cast(Type* type, Expression* val, Location location)
-{
- if (type->is_error_type() || val->is_error_expression())
- return Expression::make_error(location);
- return new Type_conversion_expression(type, val, location);
-}
-
-// An unsafe type conversion, used to pass values to builtin functions.
-
-class Unsafe_type_conversion_expression : public Expression
-{
- public:
- Unsafe_type_conversion_expression(Type* type, Expression* expr,
- Location location)
- : Expression(EXPRESSION_UNSAFE_CONVERSION, location),
- type_(type), expr_(expr)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- Type*
- do_type()
- { return this->type_; }
-
- void
- do_determine_type(const Type_context*)
- { this->expr_->determine_type_no_context(); }
-
- Expression*
- do_copy()
- {
- return new Unsafe_type_conversion_expression(this->type_,
- this->expr_->copy(),
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type to convert to.
- Type* type_;
- // The expression to convert.
- Expression* expr_;
-};
-
-// Traversal.
-
-int
-Unsafe_type_conversion_expression::do_traverse(Traverse* traverse)
-{
- if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT
- || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Convert to backend representation.
-
-tree
-Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
-{
- // We are only called for a limited number of cases.
-
- Type* t = this->type_;
- Type* et = this->expr_->type();
-
- tree type_tree = type_to_tree(this->type_->get_backend(context->gogo()));
- tree expr_tree = this->expr_->get_tree(context);
- if (type_tree == error_mark_node || expr_tree == error_mark_node)
- return error_mark_node;
-
- Location loc = this->location();
-
- bool use_view_convert = false;
- if (t->is_slice_type())
- {
- go_assert(et->is_slice_type());
- use_view_convert = true;
- }
- else if (t->map_type() != NULL)
- go_assert(et->map_type() != NULL);
- else if (t->channel_type() != NULL)
- go_assert(et->channel_type() != NULL);
- else if (t->points_to() != NULL)
- go_assert(et->points_to() != NULL || et->is_nil_type());
- else if (et->is_unsafe_pointer_type())
- go_assert(t->points_to() != NULL);
- else if (t->interface_type() != NULL && !t->interface_type()->is_empty())
- {
- go_assert(et->interface_type() != NULL
- && !et->interface_type()->is_empty());
- use_view_convert = true;
- }
- else if (t->interface_type() != NULL && t->interface_type()->is_empty())
- {
- go_assert(et->interface_type() != NULL
- && et->interface_type()->is_empty());
- use_view_convert = true;
- }
- else if (t->integer_type() != NULL)
- {
- go_assert(et->is_boolean_type()
- || et->integer_type() != NULL
- || et->function_type() != NULL
- || et->points_to() != NULL
- || et->map_type() != NULL
- || et->channel_type() != NULL);
- return convert_to_integer(type_tree, expr_tree);
- }
- else
- go_unreachable();
-
- if (use_view_convert)
- return fold_build1_loc(loc.gcc_location(), VIEW_CONVERT_EXPR, type_tree,
- expr_tree);
- else
- return fold_convert_loc(loc.gcc_location(), type_tree, expr_tree);
-}
-
-// Dump ast representation for an unsafe type conversion expression.
-
-void
-Unsafe_type_conversion_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << "(";
- ast_dump_context->dump_expression(this->expr_);
- ast_dump_context->ostream() << ") ";
-}
-
-// Make an unsafe type conversion expression.
-
-Expression*
-Expression::make_unsafe_cast(Type* type, Expression* expr,
- Location location)
-{
- return new Unsafe_type_conversion_expression(type, expr, location);
-}
-
-// Unary expressions.
-
-class Unary_expression : public Expression
-{
- public:
- Unary_expression(Operator op, Expression* expr, Location location)
- : Expression(EXPRESSION_UNARY, location),
- op_(op), escapes_(true), create_temp_(false), expr_(expr)
- { }
-
- // Return the operator.
- Operator
- op() const
- { return this->op_; }
-
- // Return the operand.
- Expression*
- operand() const
- { return this->expr_; }
-
- // Record that an address expression does not escape.
- void
- set_does_not_escape()
- {
- go_assert(this->op_ == OPERATOR_AND);
- this->escapes_ = false;
- }
-
- // Record that this is an address expression which should create a
- // temporary variable if necessary. This is used for method calls.
- void
- set_create_temp()
- {
- go_assert(this->op_ == OPERATOR_AND);
- this->create_temp_ = true;
- }
-
- // Apply unary opcode OP to UNC, setting NC. Return true if this
- // could be done, false if not. Issue errors for overflow.
- static bool
- eval_constant(Operator op, const Numeric_constant* unc,
- Location, Numeric_constant* nc);
-
- static Expression*
- do_import(Import*);
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Expression::traverse(&this->expr_, traverse); }
-
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- bool
- do_is_constant() const;
-
- bool
- do_numeric_constant_value(Numeric_constant*) const;
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_unary(this->op_, this->expr_->copy(),
- this->location());
- }
-
- bool
- do_must_eval_subexpressions_in_order(int*) const
- { return this->op_ == OPERATOR_MULT; }
-
- bool
- do_is_addressable() const
- { return this->op_ == OPERATOR_MULT; }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_export(Export*) const;
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The unary operator to apply.
- Operator op_;
- // Normally true. False if this is an address expression which does
- // not escape the current function.
- bool escapes_;
- // True if this is an address expression which should create a
- // temporary variable if necessary.
- bool create_temp_;
- // The operand.
- Expression* expr_;
-};
-
-// If we are taking the address of a composite literal, and the
-// contents are not constant, then we want to make a heap composite
-// instead.
-
-Expression*
-Unary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
-{
- Location loc = this->location();
- Operator op = this->op_;
- Expression* expr = this->expr_;
-
- if (op == OPERATOR_MULT && expr->is_type_expression())
- return Expression::make_type(Type::make_pointer_type(expr->type()), loc);
-
- // *&x simplifies to x. *(*T)(unsafe.Pointer)(&x) does not require
- // moving x to the heap. FIXME: Is it worth doing a real escape
- // analysis here? This case is found in math/unsafe.go and is
- // therefore worth special casing.
- if (op == OPERATOR_MULT)
- {
- Expression* e = expr;
- while (e->classification() == EXPRESSION_CONVERSION)
- {
- Type_conversion_expression* te
- = static_cast<Type_conversion_expression*>(e);
- e = te->expr();
- }
-
- if (e->classification() == EXPRESSION_UNARY)
- {
- Unary_expression* ue = static_cast<Unary_expression*>(e);
- if (ue->op_ == OPERATOR_AND)
- {
- if (e == expr)
- {
- // *&x == x.
- return ue->expr_;
- }
- ue->set_does_not_escape();
- }
- }
- }
-
- // Catching an invalid indirection of unsafe.Pointer here avoid
- // having to deal with TYPE_VOID in other places.
- if (op == OPERATOR_MULT && expr->type()->is_unsafe_pointer_type())
- {
- error_at(this->location(), "invalid indirect of %<unsafe.Pointer%>");
- return Expression::make_error(this->location());
- }
-
- if (op == OPERATOR_PLUS || op == OPERATOR_MINUS || op == OPERATOR_XOR)
- {
- Numeric_constant nc;
- if (expr->numeric_constant_value(&nc))
- {
- Numeric_constant result;
- if (Unary_expression::eval_constant(op, &nc, loc, &result))
- return result.expression(loc);
- }
- }
-
- return this;
-}
-
-// Return whether a unary expression is a constant.
-
-bool
-Unary_expression::do_is_constant() const
-{
- if (this->op_ == OPERATOR_MULT)
- {
- // Indirecting through a pointer is only constant if the object
- // to which the expression points is constant, but we currently
- // have no way to determine that.
- return false;
- }
- else if (this->op_ == OPERATOR_AND)
- {
- // Taking the address of a variable is constant if it is a
- // global variable, not constant otherwise. In other cases
- // taking the address is probably not a constant.
- Var_expression* ve = this->expr_->var_expression();
- if (ve != NULL)
- {
- Named_object* no = ve->named_object();
- return no->is_variable() && no->var_value()->is_global();
- }
- return false;
- }
- else
- return this->expr_->is_constant();
-}
-
-// Apply unary opcode OP to UNC, setting NC. Return true if this
-// could be done, false if not. Issue errors for overflow.
-
-bool
-Unary_expression::eval_constant(Operator op, const Numeric_constant* unc,
- Location location, Numeric_constant* nc)
-{
- switch (op)
- {
- case OPERATOR_PLUS:
- *nc = *unc;
- return true;
-
- case OPERATOR_MINUS:
- if (unc->is_int() || unc->is_rune())
- break;
- else if (unc->is_float())
- {
- mpfr_t uval;
- unc->get_float(&uval);
- mpfr_t val;
- mpfr_init(val);
- mpfr_neg(val, uval, GMP_RNDN);
- nc->set_float(unc->type(), val);
- mpfr_clear(uval);
- mpfr_clear(val);
- return true;
- }
- else if (unc->is_complex())
- {
- mpfr_t ureal, uimag;
- unc->get_complex(&ureal, &uimag);
- mpfr_t real, imag;
- mpfr_init(real);
- mpfr_init(imag);
- mpfr_neg(real, ureal, GMP_RNDN);
- mpfr_neg(imag, uimag, GMP_RNDN);
- nc->set_complex(unc->type(), real, imag);
- mpfr_clear(ureal);
- mpfr_clear(uimag);
- mpfr_clear(real);
- mpfr_clear(imag);
- return true;
- }
- else
- go_unreachable();
-
- case OPERATOR_XOR:
- break;
-
- case OPERATOR_NOT:
- case OPERATOR_AND:
- case OPERATOR_MULT:
- return false;
-
- default:
- go_unreachable();
- }
-
- if (!unc->is_int() && !unc->is_rune())
- return false;
-
- mpz_t uval;
- if (unc->is_rune())
- unc->get_rune(&uval);
- else
- unc->get_int(&uval);
- mpz_t val;
- mpz_init(val);
-
- switch (op)
- {
- case OPERATOR_MINUS:
- mpz_neg(val, uval);
- break;
-
- case OPERATOR_NOT:
- mpz_set_ui(val, mpz_cmp_si(uval, 0) == 0 ? 1 : 0);
- break;
-
- case OPERATOR_XOR:
- {
- Type* utype = unc->type();
- if (utype->integer_type() == NULL
- || utype->integer_type()->is_abstract())
- mpz_com(val, uval);
- else
- {
- // The number of HOST_WIDE_INTs that it takes to represent
- // UVAL.
- size_t count = ((mpz_sizeinbase(uval, 2)
- + HOST_BITS_PER_WIDE_INT
- - 1)
- / HOST_BITS_PER_WIDE_INT);
-
- unsigned HOST_WIDE_INT* phwi = new unsigned HOST_WIDE_INT[count];
- memset(phwi, 0, count * sizeof(HOST_WIDE_INT));
-
- size_t obits = utype->integer_type()->bits();
-
- if (!utype->integer_type()->is_unsigned() && mpz_sgn(uval) < 0)
- {
- mpz_t adj;
- mpz_init_set_ui(adj, 1);
- mpz_mul_2exp(adj, adj, obits);
- mpz_add(uval, uval, adj);
- mpz_clear(adj);
- }
-
- size_t ecount;
- mpz_export(phwi, &ecount, -1, sizeof(HOST_WIDE_INT), 0, 0, uval);
- go_assert(ecount <= count);
-
- // Trim down to the number of words required by the type.
- size_t ocount = ((obits + HOST_BITS_PER_WIDE_INT - 1)
- / HOST_BITS_PER_WIDE_INT);
- go_assert(ocount <= count);
-
- for (size_t i = 0; i < ocount; ++i)
- phwi[i] = ~phwi[i];
-
- size_t clearbits = ocount * HOST_BITS_PER_WIDE_INT - obits;
- if (clearbits != 0)
- phwi[ocount - 1] &= (((unsigned HOST_WIDE_INT) (HOST_WIDE_INT) -1)
- >> clearbits);
-
- mpz_import(val, ocount, -1, sizeof(HOST_WIDE_INT), 0, 0, phwi);
-
- if (!utype->integer_type()->is_unsigned()
- && mpz_tstbit(val, obits - 1))
- {
- mpz_t adj;
- mpz_init_set_ui(adj, 1);
- mpz_mul_2exp(adj, adj, obits);
- mpz_sub(val, val, adj);
- mpz_clear(adj);
- }
-
- delete[] phwi;
- }
- }
- break;
-
- default:
- go_unreachable();
- }
-
- if (unc->is_rune())
- nc->set_rune(NULL, val);
- else
- nc->set_int(NULL, val);
-
- mpz_clear(uval);
- mpz_clear(val);
-
- return nc->set_type(unc->type(), true, location);
-}
-
-// Return the integral constant value of a unary expression, if it has one.
-
-bool
-Unary_expression::do_numeric_constant_value(Numeric_constant* nc) const
-{
- Numeric_constant unc;
- if (!this->expr_->numeric_constant_value(&unc))
- return false;
- return Unary_expression::eval_constant(this->op_, &unc, this->location(),
- nc);
-}
-
-// Return the type of a unary expression.
-
-Type*
-Unary_expression::do_type()
-{
- switch (this->op_)
- {
- case OPERATOR_PLUS:
- case OPERATOR_MINUS:
- case OPERATOR_NOT:
- case OPERATOR_XOR:
- return this->expr_->type();
-
- case OPERATOR_AND:
- return Type::make_pointer_type(this->expr_->type());
-
- case OPERATOR_MULT:
- {
- Type* subtype = this->expr_->type();
- Type* points_to = subtype->points_to();
- if (points_to == NULL)
- return Type::make_error_type();
- return points_to;
- }
-
- default:
- go_unreachable();
- }
-}
-
-// Determine abstract types for a unary expression.
-
-void
-Unary_expression::do_determine_type(const Type_context* context)
-{
- switch (this->op_)
- {
- case OPERATOR_PLUS:
- case OPERATOR_MINUS:
- case OPERATOR_NOT:
- case OPERATOR_XOR:
- this->expr_->determine_type(context);
- break;
-
- case OPERATOR_AND:
- // Taking the address of something.
- {
- Type* subtype = (context->type == NULL
- ? NULL
- : context->type->points_to());
- Type_context subcontext(subtype, false);
- this->expr_->determine_type(&subcontext);
- }
- break;
-
- case OPERATOR_MULT:
- // Indirecting through a pointer.
- {
- Type* subtype = (context->type == NULL
- ? NULL
- : Type::make_pointer_type(context->type));
- Type_context subcontext(subtype, false);
- this->expr_->determine_type(&subcontext);
- }
- break;
-
- default:
- go_unreachable();
- }
-}
-
-// Check types for a unary expression.
-
-void
-Unary_expression::do_check_types(Gogo*)
-{
- Type* type = this->expr_->type();
- if (type->is_error())
- {
- this->set_is_error();
- return;
- }
-
- switch (this->op_)
- {
- case OPERATOR_PLUS:
- case OPERATOR_MINUS:
- if (type->integer_type() == NULL
- && type->float_type() == NULL
- && type->complex_type() == NULL)
- this->report_error(_("expected numeric type"));
- break;
-
- case OPERATOR_NOT:
- if (!type->is_boolean_type())
- this->report_error(_("expected boolean type"));
- break;
-
- case OPERATOR_XOR:
- if (type->integer_type() == NULL
- && !type->is_boolean_type())
- this->report_error(_("expected integer or boolean type"));
- break;
-
- case OPERATOR_AND:
- if (!this->expr_->is_addressable())
- {
- if (!this->create_temp_)
- this->report_error(_("invalid operand for unary %<&%>"));
- }
- else
- this->expr_->address_taken(this->escapes_);
- break;
-
- case OPERATOR_MULT:
- // Indirecting through a pointer.
- if (type->points_to() == NULL)
- this->report_error(_("expected pointer"));
- break;
-
- default:
- go_unreachable();
- }
-}
-
-// Get a tree for a unary expression.
-
-tree
-Unary_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
- Location loc = this->location();
-
- // Taking the address of a set-and-use-temporary expression requires
- // setting the temporary and then taking the address.
- if (this->op_ == OPERATOR_AND)
- {
- Set_and_use_temporary_expression* sut =
- this->expr_->set_and_use_temporary_expression();
- if (sut != NULL)
- {
- Temporary_statement* temp = sut->temporary();
- Bvariable* bvar = temp->get_backend_variable(context);
- tree var_tree = var_to_tree(bvar);
- Expression* val = sut->expression();
- tree val_tree = val->get_tree(context);
- if (var_tree == error_mark_node || val_tree == error_mark_node)
- return error_mark_node;
- tree addr_tree = build_fold_addr_expr_loc(loc.gcc_location(),
- var_tree);
- return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(addr_tree),
- build2_loc(sut->location().gcc_location(),
- MODIFY_EXPR, void_type_node,
- var_tree, val_tree),
- addr_tree);
- }
- }
-
- tree expr = this->expr_->get_tree(context);
- if (expr == error_mark_node)
- return error_mark_node;
-
- switch (this->op_)
- {
- case OPERATOR_PLUS:
- return expr;
-
- case OPERATOR_MINUS:
- {
- tree type = TREE_TYPE(expr);
- tree compute_type = excess_precision_type(type);
- if (compute_type != NULL_TREE)
- expr = ::convert(compute_type, expr);
- tree ret = fold_build1_loc(loc.gcc_location(), NEGATE_EXPR,
- (compute_type != NULL_TREE
- ? compute_type
- : type),
- expr);
- if (compute_type != NULL_TREE)
- ret = ::convert(type, ret);
- return ret;
- }
-
- case OPERATOR_NOT:
- if (TREE_CODE(TREE_TYPE(expr)) == BOOLEAN_TYPE)
- return fold_build1_loc(loc.gcc_location(), TRUTH_NOT_EXPR,
- TREE_TYPE(expr), expr);
- else
- return fold_build2_loc(loc.gcc_location(), NE_EXPR, boolean_type_node,
- expr, build_int_cst(TREE_TYPE(expr), 0));
-
- case OPERATOR_XOR:
- return fold_build1_loc(loc.gcc_location(), BIT_NOT_EXPR, TREE_TYPE(expr),
- expr);
-
- case OPERATOR_AND:
- if (!this->create_temp_)
- {
- // We should not see a non-constant constructor here; cases
- // where we would see one should have been moved onto the
- // heap at parse time. Taking the address of a nonconstant
- // constructor will not do what the programmer expects.
- go_assert(TREE_CODE(expr) != CONSTRUCTOR || TREE_CONSTANT(expr));
- go_assert(TREE_CODE(expr) != ADDR_EXPR);
- }
-
- // Build a decl for a constant constructor.
- if (TREE_CODE(expr) == CONSTRUCTOR && TREE_CONSTANT(expr))
- {
- tree decl = build_decl(this->location().gcc_location(), VAR_DECL,
- create_tmp_var_name("C"), TREE_TYPE(expr));
- DECL_EXTERNAL(decl) = 0;
- TREE_PUBLIC(decl) = 0;
- TREE_READONLY(decl) = 1;
- TREE_CONSTANT(decl) = 1;
- TREE_STATIC(decl) = 1;
- TREE_ADDRESSABLE(decl) = 1;
- DECL_ARTIFICIAL(decl) = 1;
- DECL_INITIAL(decl) = expr;
- rest_of_decl_compilation(decl, 1, 0);
- expr = decl;
- }
-
- if (this->create_temp_
- && !TREE_ADDRESSABLE(TREE_TYPE(expr))
- && (TREE_CODE(expr) == CONST_DECL || !DECL_P(expr))
- && TREE_CODE(expr) != INDIRECT_REF
- && TREE_CODE(expr) != COMPONENT_REF)
- {
- if (current_function_decl != NULL)
- {
- tree tmp = create_tmp_var(TREE_TYPE(expr), get_name(expr));
- DECL_IGNORED_P(tmp) = 1;
- DECL_INITIAL(tmp) = expr;
- TREE_ADDRESSABLE(tmp) = 1;
- return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
- build_pointer_type(TREE_TYPE(expr)),
- build1_loc(loc.gcc_location(), DECL_EXPR,
- void_type_node, tmp),
- build_fold_addr_expr_loc(loc.gcc_location(),
- tmp));
- }
- else
- {
- tree tmp = build_decl(loc.gcc_location(), VAR_DECL,
- create_tmp_var_name("A"), TREE_TYPE(expr));
- DECL_EXTERNAL(tmp) = 0;
- TREE_PUBLIC(tmp) = 0;
- TREE_STATIC(tmp) = 1;
- DECL_ARTIFICIAL(tmp) = 1;
- TREE_ADDRESSABLE(tmp) = 1;
- tree make_tmp;
- if (!TREE_CONSTANT(expr))
- make_tmp = fold_build2_loc(loc.gcc_location(), INIT_EXPR,
- void_type_node, tmp, expr);
- else
- {
- TREE_READONLY(tmp) = 1;
- TREE_CONSTANT(tmp) = 1;
- DECL_INITIAL(tmp) = expr;
- make_tmp = NULL_TREE;
- }
- rest_of_decl_compilation(tmp, 1, 0);
- tree addr = build_fold_addr_expr_loc(loc.gcc_location(), tmp);
- if (make_tmp == NULL_TREE)
- return addr;
- return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(addr), make_tmp, addr);
- }
- }
-
- return build_fold_addr_expr_loc(loc.gcc_location(), expr);
-
- case OPERATOR_MULT:
- {
- go_assert(POINTER_TYPE_P(TREE_TYPE(expr)));
-
- // If we are dereferencing the pointer to a large struct, we
- // need to check for nil. We don't bother to check for small
- // structs because we expect the system to crash on a nil
- // pointer dereference.
- tree target_type_tree = TREE_TYPE(TREE_TYPE(expr));
- if (!VOID_TYPE_P(target_type_tree))
- {
- HOST_WIDE_INT s = int_size_in_bytes(target_type_tree);
- if (s == -1 || s >= 4096)
- {
- if (!DECL_P(expr))
- expr = save_expr(expr);
- tree compare = fold_build2_loc(loc.gcc_location(), EQ_EXPR,
- boolean_type_node,
- expr,
- fold_convert(TREE_TYPE(expr),
- null_pointer_node));
- tree crash = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
- loc);
- expr = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(expr), build3(COND_EXPR,
- void_type_node,
- compare, crash,
- NULL_TREE),
- expr);
- }
- }
-
- // If the type of EXPR is a recursive pointer type, then we
- // need to insert a cast before indirecting.
- if (VOID_TYPE_P(target_type_tree))
- {
- Type* pt = this->expr_->type()->points_to();
- tree ind = type_to_tree(pt->get_backend(gogo));
- expr = fold_convert_loc(loc.gcc_location(),
- build_pointer_type(ind), expr);
- }
-
- return build_fold_indirect_ref_loc(loc.gcc_location(), expr);
- }
-
- default:
- go_unreachable();
- }
-}
-
-// Export a unary expression.
-
-void
-Unary_expression::do_export(Export* exp) const
-{
- switch (this->op_)
- {
- case OPERATOR_PLUS:
- exp->write_c_string("+ ");
- break;
- case OPERATOR_MINUS:
- exp->write_c_string("- ");
- break;
- case OPERATOR_NOT:
- exp->write_c_string("! ");
- break;
- case OPERATOR_XOR:
- exp->write_c_string("^ ");
- break;
- case OPERATOR_AND:
- case OPERATOR_MULT:
- default:
- go_unreachable();
- }
- this->expr_->export_expression(exp);
-}
-
-// Import a unary expression.
-
-Expression*
-Unary_expression::do_import(Import* imp)
-{
- Operator op;
- switch (imp->get_char())
- {
- case '+':
- op = OPERATOR_PLUS;
- break;
- case '-':
- op = OPERATOR_MINUS;
- break;
- case '!':
- op = OPERATOR_NOT;
- break;
- case '^':
- op = OPERATOR_XOR;
- break;
- default:
- go_unreachable();
- }
- imp->require_c_string(" ");
- Expression* expr = Expression::import_expression(imp);
- return Expression::make_unary(op, expr, imp->location());
-}
-
-// Dump ast representation of an unary expression.
-
-void
-Unary_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->dump_operator(this->op_);
- ast_dump_context->ostream() << "(";
- ast_dump_context->dump_expression(this->expr_);
- ast_dump_context->ostream() << ") ";
-}
-
-// Make a unary expression.
-
-Expression*
-Expression::make_unary(Operator op, Expression* expr, Location location)
-{
- return new Unary_expression(op, expr, location);
-}
-
-// If this is an indirection through a pointer, return the expression
-// being pointed through. Otherwise return this.
-
-Expression*
-Expression::deref()
-{
- if (this->classification_ == EXPRESSION_UNARY)
- {
- Unary_expression* ue = static_cast<Unary_expression*>(this);
- if (ue->op() == OPERATOR_MULT)
- return ue->operand();
- }
- return this;
-}
-
-// Class Binary_expression.
-
-// Traversal.
-
-int
-Binary_expression::do_traverse(Traverse* traverse)
-{
- int t = Expression::traverse(&this->left_, traverse);
- if (t == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return Expression::traverse(&this->right_, traverse);
-}
-
-// Return the type to use for a binary operation on operands of
-// LEFT_TYPE and RIGHT_TYPE. These are the types of constants and as
-// such may be NULL or abstract.
-
-bool
-Binary_expression::operation_type(Operator op, Type* left_type,
- Type* right_type, Type** result_type)
-{
- if (left_type != right_type
- && !left_type->is_abstract()
- && !right_type->is_abstract()
- && left_type->base() != right_type->base()
- && op != OPERATOR_LSHIFT
- && op != OPERATOR_RSHIFT)
- {
- // May be a type error--let it be diagnosed elsewhere.
- return false;
- }
-
- if (op == OPERATOR_LSHIFT || op == OPERATOR_RSHIFT)
- {
- if (left_type->integer_type() != NULL)
- *result_type = left_type;
- else
- *result_type = Type::make_abstract_integer_type();
- }
- else if (!left_type->is_abstract() && left_type->named_type() != NULL)
- *result_type = left_type;
- else if (!right_type->is_abstract() && right_type->named_type() != NULL)
- *result_type = right_type;
- else if (!left_type->is_abstract())
- *result_type = left_type;
- else if (!right_type->is_abstract())
- *result_type = right_type;
- else if (left_type->complex_type() != NULL)
- *result_type = left_type;
- else if (right_type->complex_type() != NULL)
- *result_type = right_type;
- else if (left_type->float_type() != NULL)
- *result_type = left_type;
- else if (right_type->float_type() != NULL)
- *result_type = right_type;
- else if (left_type->integer_type() != NULL
- && left_type->integer_type()->is_rune())
- *result_type = left_type;
- else if (right_type->integer_type() != NULL
- && right_type->integer_type()->is_rune())
- *result_type = right_type;
- else
- *result_type = left_type;
-
- return true;
-}
-
-// Convert an integer comparison code and an operator to a boolean
-// value.
-
-bool
-Binary_expression::cmp_to_bool(Operator op, int cmp)
-{
- switch (op)
- {
- case OPERATOR_EQEQ:
- return cmp == 0;
- break;
- case OPERATOR_NOTEQ:
- return cmp != 0;
- break;
- case OPERATOR_LT:
- return cmp < 0;
- break;
- case OPERATOR_LE:
- return cmp <= 0;
- case OPERATOR_GT:
- return cmp > 0;
- case OPERATOR_GE:
- return cmp >= 0;
- default:
- go_unreachable();
- }
-}
-
-// Compare constants according to OP.
-
-bool
-Binary_expression::compare_constant(Operator op, Numeric_constant* left_nc,
- Numeric_constant* right_nc,
- Location location, bool* result)
-{
- Type* left_type = left_nc->type();
- Type* right_type = right_nc->type();
-
- Type* type;
- if (!Binary_expression::operation_type(op, left_type, right_type, &type))
- return false;
-
- // When comparing an untyped operand to a typed operand, we are
- // effectively coercing the untyped operand to the other operand's
- // type, so make sure that is valid.
- if (!left_nc->set_type(type, true, location)
- || !right_nc->set_type(type, true, location))
- return false;
-
- bool ret;
- int cmp;
- if (type->complex_type() != NULL)
- {
- if (op != OPERATOR_EQEQ && op != OPERATOR_NOTEQ)
- return false;
- ret = Binary_expression::compare_complex(left_nc, right_nc, &cmp);
- }
- else if (type->float_type() != NULL)
- ret = Binary_expression::compare_float(left_nc, right_nc, &cmp);
- else
- ret = Binary_expression::compare_integer(left_nc, right_nc, &cmp);
-
- if (ret)
- *result = Binary_expression::cmp_to_bool(op, cmp);
-
- return ret;
-}
-
-// Compare integer constants.
-
-bool
-Binary_expression::compare_integer(const Numeric_constant* left_nc,
- const Numeric_constant* right_nc,
- int* cmp)
-{
- mpz_t left_val;
- if (!left_nc->to_int(&left_val))
- return false;
- mpz_t right_val;
- if (!right_nc->to_int(&right_val))
- {
- mpz_clear(left_val);
- return false;
- }
-
- *cmp = mpz_cmp(left_val, right_val);
-
- mpz_clear(left_val);
- mpz_clear(right_val);
-
- return true;
-}
-
-// Compare floating point constants.
-
-bool
-Binary_expression::compare_float(const Numeric_constant* left_nc,
- const Numeric_constant* right_nc,
- int* cmp)
-{
- mpfr_t left_val;
- if (!left_nc->to_float(&left_val))
- return false;
- mpfr_t right_val;
- if (!right_nc->to_float(&right_val))
- {
- mpfr_clear(left_val);
- return false;
- }
-
- // We already coerced both operands to the same type. If that type
- // is not an abstract type, we need to round the values accordingly.
- Type* type = left_nc->type();
- if (!type->is_abstract() && type->float_type() != NULL)
- {
- int bits = type->float_type()->bits();
- mpfr_prec_round(left_val, bits, GMP_RNDN);
- mpfr_prec_round(right_val, bits, GMP_RNDN);
- }
-
- *cmp = mpfr_cmp(left_val, right_val);
-
- mpfr_clear(left_val);
- mpfr_clear(right_val);
-
- return true;
-}
-
-// Compare complex constants. Complex numbers may only be compared
-// for equality.
-
-bool
-Binary_expression::compare_complex(const Numeric_constant* left_nc,
- const Numeric_constant* right_nc,
- int* cmp)
-{
- mpfr_t left_real, left_imag;
- if (!left_nc->to_complex(&left_real, &left_imag))
- return false;
- mpfr_t right_real, right_imag;
- if (!right_nc->to_complex(&right_real, &right_imag))
- {
- mpfr_clear(left_real);
- mpfr_clear(left_imag);
- return false;
- }
-
- // We already coerced both operands to the same type. If that type
- // is not an abstract type, we need to round the values accordingly.
- Type* type = left_nc->type();
- if (!type->is_abstract() && type->complex_type() != NULL)
- {
- int bits = type->complex_type()->bits();
- mpfr_prec_round(left_real, bits / 2, GMP_RNDN);
- mpfr_prec_round(left_imag, bits / 2, GMP_RNDN);
- mpfr_prec_round(right_real, bits / 2, GMP_RNDN);
- mpfr_prec_round(right_imag, bits / 2, GMP_RNDN);
- }
-
- *cmp = (mpfr_cmp(left_real, right_real) != 0
- || mpfr_cmp(left_imag, right_imag) != 0);
-
- mpfr_clear(left_real);
- mpfr_clear(left_imag);
- mpfr_clear(right_real);
- mpfr_clear(right_imag);
-
- return true;
-}
-
-// Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC. Return
-// true if this could be done, false if not. Issue errors at LOCATION
-// as appropriate.
-
-bool
-Binary_expression::eval_constant(Operator op, Numeric_constant* left_nc,
- Numeric_constant* right_nc,
- Location location, Numeric_constant* nc)
-{
- switch (op)
- {
- case OPERATOR_OROR:
- case OPERATOR_ANDAND:
- case OPERATOR_EQEQ:
- case OPERATOR_NOTEQ:
- case OPERATOR_LT:
- case OPERATOR_LE:
- case OPERATOR_GT:
- case OPERATOR_GE:
- // These return boolean values, not numeric.
- return false;
- default:
- break;
- }
-
- Type* left_type = left_nc->type();
- Type* right_type = right_nc->type();
-
- Type* type;
- if (!Binary_expression::operation_type(op, left_type, right_type, &type))
- return false;
-
- bool is_shift = op == OPERATOR_LSHIFT || op == OPERATOR_RSHIFT;
-
- // When combining an untyped operand with a typed operand, we are
- // effectively coercing the untyped operand to the other operand's
- // type, so make sure that is valid.
- if (!left_nc->set_type(type, true, location))
- return false;
- if (!is_shift && !right_nc->set_type(type, true, location))
- return false;
-
- bool r;
- if (type->complex_type() != NULL)
- r = Binary_expression::eval_complex(op, left_nc, right_nc, location, nc);
- else if (type->float_type() != NULL)
- r = Binary_expression::eval_float(op, left_nc, right_nc, location, nc);
- else
- r = Binary_expression::eval_integer(op, left_nc, right_nc, location, nc);
-
- if (r)
- r = nc->set_type(type, true, location);
-
- return r;
-}
-
-// Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC, using
-// integer operations. Return true if this could be done, false if
-// not.
-
-bool
-Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
- const Numeric_constant* right_nc,
- Location location, Numeric_constant* nc)
-{
- mpz_t left_val;
- if (!left_nc->to_int(&left_val))
- return false;
- mpz_t right_val;
- if (!right_nc->to_int(&right_val))
- {
- mpz_clear(left_val);
- return false;
- }
-
- mpz_t val;
- mpz_init(val);
-
- switch (op)
- {
- case OPERATOR_PLUS:
- mpz_add(val, left_val, right_val);
- break;
- case OPERATOR_MINUS:
- mpz_sub(val, left_val, right_val);
- break;
- case OPERATOR_OR:
- mpz_ior(val, left_val, right_val);
- break;
- case OPERATOR_XOR:
- mpz_xor(val, left_val, right_val);
- break;
- case OPERATOR_MULT:
- mpz_mul(val, left_val, right_val);
- break;
- case OPERATOR_DIV:
- if (mpz_sgn(right_val) != 0)
- mpz_tdiv_q(val, left_val, right_val);
- else
- {
- error_at(location, "division by zero");
- mpz_set_ui(val, 0);
- }
- break;
- case OPERATOR_MOD:
- if (mpz_sgn(right_val) != 0)
- mpz_tdiv_r(val, left_val, right_val);
- else
- {
- error_at(location, "division by zero");
- mpz_set_ui(val, 0);
- }
- break;
- case OPERATOR_LSHIFT:
- {
- unsigned long shift = mpz_get_ui(right_val);
- if (mpz_cmp_ui(right_val, shift) == 0 && shift <= 0x100000)
- mpz_mul_2exp(val, left_val, shift);
- else
- {
- error_at(location, "shift count overflow");
- mpz_set_ui(val, 0);
- }
- break;
- }
- break;
- case OPERATOR_RSHIFT:
- {
- unsigned long shift = mpz_get_ui(right_val);
- if (mpz_cmp_ui(right_val, shift) != 0)
- {
- error_at(location, "shift count overflow");
- mpz_set_ui(val, 0);
- }
- else
- {
- if (mpz_cmp_ui(left_val, 0) >= 0)
- mpz_tdiv_q_2exp(val, left_val, shift);
- else
- mpz_fdiv_q_2exp(val, left_val, shift);
- }
- break;
- }
- break;
- case OPERATOR_AND:
- mpz_and(val, left_val, right_val);
- break;
- case OPERATOR_BITCLEAR:
- {
- mpz_t tval;
- mpz_init(tval);
- mpz_com(tval, right_val);
- mpz_and(val, left_val, tval);
- mpz_clear(tval);
- }
- break;
- default:
- go_unreachable();
- }
-
- mpz_clear(left_val);
- mpz_clear(right_val);
-
- if (left_nc->is_rune()
- || (op != OPERATOR_LSHIFT
- && op != OPERATOR_RSHIFT
- && right_nc->is_rune()))
- nc->set_rune(NULL, val);
- else
- nc->set_int(NULL, val);
-
- mpz_clear(val);
-
- return true;
-}
-
-// Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC, using
-// floating point operations. Return true if this could be done,
-// false if not.
-
-bool
-Binary_expression::eval_float(Operator op, const Numeric_constant* left_nc,
- const Numeric_constant* right_nc,
- Location location, Numeric_constant* nc)
-{
- mpfr_t left_val;
- if (!left_nc->to_float(&left_val))
- return false;
- mpfr_t right_val;
- if (!right_nc->to_float(&right_val))
- {
- mpfr_clear(left_val);
- return false;
- }
-
- mpfr_t val;
- mpfr_init(val);
-
- bool ret = true;
- switch (op)
- {
- case OPERATOR_PLUS:
- mpfr_add(val, left_val, right_val, GMP_RNDN);
- break;
- case OPERATOR_MINUS:
- mpfr_sub(val, left_val, right_val, GMP_RNDN);
- break;
- case OPERATOR_OR:
- case OPERATOR_XOR:
- case OPERATOR_AND:
- case OPERATOR_BITCLEAR:
- case OPERATOR_MOD:
- case OPERATOR_LSHIFT:
- case OPERATOR_RSHIFT:
- mpfr_set_ui(val, 0, GMP_RNDN);
- ret = false;
- break;
- case OPERATOR_MULT:
- mpfr_mul(val, left_val, right_val, GMP_RNDN);
- break;
- case OPERATOR_DIV:
- if (!mpfr_zero_p(right_val))
- mpfr_div(val, left_val, right_val, GMP_RNDN);
- else
- {
- error_at(location, "division by zero");
- mpfr_set_ui(val, 0, GMP_RNDN);
- }
- break;
- default:
- go_unreachable();
- }
-
- mpfr_clear(left_val);
- mpfr_clear(right_val);
-
- nc->set_float(NULL, val);
- mpfr_clear(val);
-
- return ret;
-}
-
-// Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC, using
-// complex operations. Return true if this could be done, false if
-// not.
-
-bool
-Binary_expression::eval_complex(Operator op, const Numeric_constant* left_nc,
- const Numeric_constant* right_nc,
- Location location, Numeric_constant* nc)
-{
- mpfr_t left_real, left_imag;
- if (!left_nc->to_complex(&left_real, &left_imag))
- return false;
- mpfr_t right_real, right_imag;
- if (!right_nc->to_complex(&right_real, &right_imag))
- {
- mpfr_clear(left_real);
- mpfr_clear(left_imag);
- return false;
- }
-
- mpfr_t real, imag;
- mpfr_init(real);
- mpfr_init(imag);
-
- bool ret = true;
- switch (op)
- {
- case OPERATOR_PLUS:
- mpfr_add(real, left_real, right_real, GMP_RNDN);
- mpfr_add(imag, left_imag, right_imag, GMP_RNDN);
- break;
- case OPERATOR_MINUS:
- mpfr_sub(real, left_real, right_real, GMP_RNDN);
- mpfr_sub(imag, left_imag, right_imag, GMP_RNDN);
- break;
- case OPERATOR_OR:
- case OPERATOR_XOR:
- case OPERATOR_AND:
- case OPERATOR_BITCLEAR:
- case OPERATOR_MOD:
- case OPERATOR_LSHIFT:
- case OPERATOR_RSHIFT:
- mpfr_set_ui(real, 0, GMP_RNDN);
- mpfr_set_ui(imag, 0, GMP_RNDN);
- ret = false;
- break;
- case OPERATOR_MULT:
- {
- // You might think that multiplying two complex numbers would
- // be simple, and you would be right, until you start to think
- // about getting the right answer for infinity. If one
- // operand here is infinity and the other is anything other
- // than zero or NaN, then we are going to wind up subtracting
- // two infinity values. That will give us a NaN, but the
- // correct answer is infinity.
-
- mpfr_t lrrr;
- mpfr_init(lrrr);
- mpfr_mul(lrrr, left_real, right_real, GMP_RNDN);
-
- mpfr_t lrri;
- mpfr_init(lrri);
- mpfr_mul(lrri, left_real, right_imag, GMP_RNDN);
-
- mpfr_t lirr;
- mpfr_init(lirr);
- mpfr_mul(lirr, left_imag, right_real, GMP_RNDN);
-
- mpfr_t liri;
- mpfr_init(liri);
- mpfr_mul(liri, left_imag, right_imag, GMP_RNDN);
-
- mpfr_sub(real, lrrr, liri, GMP_RNDN);
- mpfr_add(imag, lrri, lirr, GMP_RNDN);
-
- // If we get NaN on both sides, check whether it should really
- // be infinity. The rule is that if either side of the
- // complex number is infinity, then the whole value is
- // infinity, even if the other side is NaN. So the only case
- // we have to fix is the one in which both sides are NaN.
- if (mpfr_nan_p(real) && mpfr_nan_p(imag)
- && (!mpfr_nan_p(left_real) || !mpfr_nan_p(left_imag))
- && (!mpfr_nan_p(right_real) || !mpfr_nan_p(right_imag)))
- {
- bool is_infinity = false;
-
- mpfr_t lr;
- mpfr_t li;
- mpfr_init_set(lr, left_real, GMP_RNDN);
- mpfr_init_set(li, left_imag, GMP_RNDN);
-
- mpfr_t rr;
- mpfr_t ri;
- mpfr_init_set(rr, right_real, GMP_RNDN);
- mpfr_init_set(ri, right_imag, GMP_RNDN);
-
- // If the left side is infinity, then the result is
- // infinity.
- if (mpfr_inf_p(lr) || mpfr_inf_p(li))
- {
- mpfr_set_ui(lr, mpfr_inf_p(lr) ? 1 : 0, GMP_RNDN);
- mpfr_copysign(lr, lr, left_real, GMP_RNDN);
- mpfr_set_ui(li, mpfr_inf_p(li) ? 1 : 0, GMP_RNDN);
- mpfr_copysign(li, li, left_imag, GMP_RNDN);
- if (mpfr_nan_p(rr))
- {
- mpfr_set_ui(rr, 0, GMP_RNDN);
- mpfr_copysign(rr, rr, right_real, GMP_RNDN);
- }
- if (mpfr_nan_p(ri))
- {
- mpfr_set_ui(ri, 0, GMP_RNDN);
- mpfr_copysign(ri, ri, right_imag, GMP_RNDN);
- }
- is_infinity = true;
- }
-
- // If the right side is infinity, then the result is
- // infinity.
- if (mpfr_inf_p(rr) || mpfr_inf_p(ri))
- {
- mpfr_set_ui(rr, mpfr_inf_p(rr) ? 1 : 0, GMP_RNDN);
- mpfr_copysign(rr, rr, right_real, GMP_RNDN);
- mpfr_set_ui(ri, mpfr_inf_p(ri) ? 1 : 0, GMP_RNDN);
- mpfr_copysign(ri, ri, right_imag, GMP_RNDN);
- if (mpfr_nan_p(lr))
- {
- mpfr_set_ui(lr, 0, GMP_RNDN);
- mpfr_copysign(lr, lr, left_real, GMP_RNDN);
- }
- if (mpfr_nan_p(li))
- {
- mpfr_set_ui(li, 0, GMP_RNDN);
- mpfr_copysign(li, li, left_imag, GMP_RNDN);
- }
- is_infinity = true;
- }
-
- // If we got an overflow in the intermediate computations,
- // then the result is infinity.
- if (!is_infinity
- && (mpfr_inf_p(lrrr) || mpfr_inf_p(lrri)
- || mpfr_inf_p(lirr) || mpfr_inf_p(liri)))
- {
- if (mpfr_nan_p(lr))
- {
- mpfr_set_ui(lr, 0, GMP_RNDN);
- mpfr_copysign(lr, lr, left_real, GMP_RNDN);
- }
- if (mpfr_nan_p(li))
- {
- mpfr_set_ui(li, 0, GMP_RNDN);
- mpfr_copysign(li, li, left_imag, GMP_RNDN);
- }
- if (mpfr_nan_p(rr))
- {
- mpfr_set_ui(rr, 0, GMP_RNDN);
- mpfr_copysign(rr, rr, right_real, GMP_RNDN);
- }
- if (mpfr_nan_p(ri))
- {
- mpfr_set_ui(ri, 0, GMP_RNDN);
- mpfr_copysign(ri, ri, right_imag, GMP_RNDN);
- }
- is_infinity = true;
- }
-
- if (is_infinity)
- {
- mpfr_mul(lrrr, lr, rr, GMP_RNDN);
- mpfr_mul(lrri, lr, ri, GMP_RNDN);
- mpfr_mul(lirr, li, rr, GMP_RNDN);
- mpfr_mul(liri, li, ri, GMP_RNDN);
- mpfr_sub(real, lrrr, liri, GMP_RNDN);
- mpfr_add(imag, lrri, lirr, GMP_RNDN);
- mpfr_set_inf(real, mpfr_sgn(real));
- mpfr_set_inf(imag, mpfr_sgn(imag));
- }
-
- mpfr_clear(lr);
- mpfr_clear(li);
- mpfr_clear(rr);
- mpfr_clear(ri);
- }
-
- mpfr_clear(lrrr);
- mpfr_clear(lrri);
- mpfr_clear(lirr);
- mpfr_clear(liri);
- }
- break;
- case OPERATOR_DIV:
- {
- // For complex division we want to avoid having an
- // intermediate overflow turn the whole result in a NaN. We
- // scale the values to try to avoid this.
-
- if (mpfr_zero_p(right_real) && mpfr_zero_p(right_imag))
- {
- error_at(location, "division by zero");
- mpfr_set_ui(real, 0, GMP_RNDN);
- mpfr_set_ui(imag, 0, GMP_RNDN);
- break;
- }
-
- mpfr_t rra;
- mpfr_t ria;
- mpfr_init(rra);
- mpfr_init(ria);
- mpfr_abs(rra, right_real, GMP_RNDN);
- mpfr_abs(ria, right_imag, GMP_RNDN);
- mpfr_t t;
- mpfr_init(t);
- mpfr_max(t, rra, ria, GMP_RNDN);
-
- mpfr_t rr;
- mpfr_t ri;
- mpfr_init_set(rr, right_real, GMP_RNDN);
- mpfr_init_set(ri, right_imag, GMP_RNDN);
- long ilogbw = 0;
- if (!mpfr_inf_p(t) && !mpfr_nan_p(t) && !mpfr_zero_p(t))
- {
- ilogbw = mpfr_get_exp(t);
- mpfr_mul_2si(rr, rr, - ilogbw, GMP_RNDN);
- mpfr_mul_2si(ri, ri, - ilogbw, GMP_RNDN);
- }
-
- mpfr_t denom;
- mpfr_init(denom);
- mpfr_mul(denom, rr, rr, GMP_RNDN);
- mpfr_mul(t, ri, ri, GMP_RNDN);
- mpfr_add(denom, denom, t, GMP_RNDN);
-
- mpfr_mul(real, left_real, rr, GMP_RNDN);
- mpfr_mul(t, left_imag, ri, GMP_RNDN);
- mpfr_add(real, real, t, GMP_RNDN);
- mpfr_div(real, real, denom, GMP_RNDN);
- mpfr_mul_2si(real, real, - ilogbw, GMP_RNDN);
-
- mpfr_mul(imag, left_imag, rr, GMP_RNDN);
- mpfr_mul(t, left_real, ri, GMP_RNDN);
- mpfr_sub(imag, imag, t, GMP_RNDN);
- mpfr_div(imag, imag, denom, GMP_RNDN);
- mpfr_mul_2si(imag, imag, - ilogbw, GMP_RNDN);
-
- // If we wind up with NaN on both sides, check whether we
- // should really have infinity. The rule is that if either
- // side of the complex number is infinity, then the whole
- // value is infinity, even if the other side is NaN. So the
- // only case we have to fix is the one in which both sides are
- // NaN.
- if (mpfr_nan_p(real) && mpfr_nan_p(imag)
- && (!mpfr_nan_p(left_real) || !mpfr_nan_p(left_imag))
- && (!mpfr_nan_p(right_real) || !mpfr_nan_p(right_imag)))
- {
- if (mpfr_zero_p(denom))
- {
- mpfr_set_inf(real, mpfr_sgn(rr));
- mpfr_mul(real, real, left_real, GMP_RNDN);
- mpfr_set_inf(imag, mpfr_sgn(rr));
- mpfr_mul(imag, imag, left_imag, GMP_RNDN);
- }
- else if ((mpfr_inf_p(left_real) || mpfr_inf_p(left_imag))
- && mpfr_number_p(rr) && mpfr_number_p(ri))
- {
- mpfr_set_ui(t, mpfr_inf_p(left_real) ? 1 : 0, GMP_RNDN);
- mpfr_copysign(t, t, left_real, GMP_RNDN);
-
- mpfr_t t2;
- mpfr_init_set_ui(t2, mpfr_inf_p(left_imag) ? 1 : 0, GMP_RNDN);
- mpfr_copysign(t2, t2, left_imag, GMP_RNDN);
-
- mpfr_t t3;
- mpfr_init(t3);
- mpfr_mul(t3, t, rr, GMP_RNDN);
-
- mpfr_t t4;
- mpfr_init(t4);
- mpfr_mul(t4, t2, ri, GMP_RNDN);
-
- mpfr_add(t3, t3, t4, GMP_RNDN);
- mpfr_set_inf(real, mpfr_sgn(t3));
-
- mpfr_mul(t3, t2, rr, GMP_RNDN);
- mpfr_mul(t4, t, ri, GMP_RNDN);
- mpfr_sub(t3, t3, t4, GMP_RNDN);
- mpfr_set_inf(imag, mpfr_sgn(t3));
-
- mpfr_clear(t2);
- mpfr_clear(t3);
- mpfr_clear(t4);
- }
- else if ((mpfr_inf_p(right_real) || mpfr_inf_p(right_imag))
- && mpfr_number_p(left_real) && mpfr_number_p(left_imag))
- {
- mpfr_set_ui(t, mpfr_inf_p(rr) ? 1 : 0, GMP_RNDN);
- mpfr_copysign(t, t, rr, GMP_RNDN);
-
- mpfr_t t2;
- mpfr_init_set_ui(t2, mpfr_inf_p(ri) ? 1 : 0, GMP_RNDN);
- mpfr_copysign(t2, t2, ri, GMP_RNDN);
-
- mpfr_t t3;
- mpfr_init(t3);
- mpfr_mul(t3, left_real, t, GMP_RNDN);
-
- mpfr_t t4;
- mpfr_init(t4);
- mpfr_mul(t4, left_imag, t2, GMP_RNDN);
-
- mpfr_add(t3, t3, t4, GMP_RNDN);
- mpfr_set_ui(real, 0, GMP_RNDN);
- mpfr_mul(real, real, t3, GMP_RNDN);
-
- mpfr_mul(t3, left_imag, t, GMP_RNDN);
- mpfr_mul(t4, left_real, t2, GMP_RNDN);
- mpfr_sub(t3, t3, t4, GMP_RNDN);
- mpfr_set_ui(imag, 0, GMP_RNDN);
- mpfr_mul(imag, imag, t3, GMP_RNDN);
-
- mpfr_clear(t2);
- mpfr_clear(t3);
- mpfr_clear(t4);
- }
- }
-
- mpfr_clear(denom);
- mpfr_clear(rr);
- mpfr_clear(ri);
- mpfr_clear(t);
- mpfr_clear(rra);
- mpfr_clear(ria);
- }
- break;
- default:
- go_unreachable();
- }
-
- mpfr_clear(left_real);
- mpfr_clear(left_imag);
- mpfr_clear(right_real);
- mpfr_clear(right_imag);
-
- nc->set_complex(NULL, real, imag);
- mpfr_clear(real);
- mpfr_clear(imag);
-
- return ret;
-}
-
-// Lower a binary expression. We have to evaluate constant
-// expressions now, in order to implement Go's unlimited precision
-// constants.
-
-Expression*
-Binary_expression::do_lower(Gogo* gogo, Named_object*,
- Statement_inserter* inserter, int)
-{
- Location location = this->location();
- Operator op = this->op_;
- Expression* left = this->left_;
- Expression* right = this->right_;
-
- const bool is_comparison = (op == OPERATOR_EQEQ
- || op == OPERATOR_NOTEQ
- || op == OPERATOR_LT
- || op == OPERATOR_LE
- || op == OPERATOR_GT
- || op == OPERATOR_GE);
-
- // Numeric constant expressions.
- {
- Numeric_constant left_nc;
- Numeric_constant right_nc;
- if (left->numeric_constant_value(&left_nc)
- && right->numeric_constant_value(&right_nc))
- {
- if (is_comparison)
- {
- bool result;
- if (!Binary_expression::compare_constant(op, &left_nc,
- &right_nc, location,
- &result))
- return this;
- return Expression::make_cast(Type::make_boolean_type(),
- Expression::make_boolean(result,
- location),
- location);
- }
- else
- {
- Numeric_constant nc;
- if (!Binary_expression::eval_constant(op, &left_nc, &right_nc,
- location, &nc))
- return this;
- return nc.expression(location);
- }
- }
- }
-
- // String constant expressions.
- if (left->type()->is_string_type() && right->type()->is_string_type())
- {
- std::string left_string;
- std::string right_string;
- if (left->string_constant_value(&left_string)
- && right->string_constant_value(&right_string))
- {
- if (op == OPERATOR_PLUS)
- return Expression::make_string(left_string + right_string,
- location);
- else if (is_comparison)
- {
- int cmp = left_string.compare(right_string);
- bool r = Binary_expression::cmp_to_bool(op, cmp);
- return Expression::make_boolean(r, location);
- }
- }
- }
-
- // Lower struct and array comparisons.
- if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
- {
- if (left->type()->struct_type() != NULL)
- return this->lower_struct_comparison(gogo, inserter);
- else if (left->type()->array_type() != NULL
- && !left->type()->is_slice_type())
- return this->lower_array_comparison(gogo, inserter);
- }
-
- return this;
-}
-
-// Lower a struct comparison.
-
-Expression*
-Binary_expression::lower_struct_comparison(Gogo* gogo,
- Statement_inserter* inserter)
-{
- Struct_type* st = this->left_->type()->struct_type();
- Struct_type* st2 = this->right_->type()->struct_type();
- if (st2 == NULL)
- return this;
- if (st != st2 && !Type::are_identical(st, st2, false, NULL))
- return this;
- if (!Type::are_compatible_for_comparison(true, this->left_->type(),
- this->right_->type(), NULL))
- return this;
-
- // See if we can compare using memcmp. As a heuristic, we use
- // memcmp rather than field references and comparisons if there are
- // more than two fields.
- if (st->compare_is_identity(gogo) && st->total_field_count() > 2)
- return this->lower_compare_to_memcmp(gogo, inserter);
-
- Location loc = this->location();
-
- Expression* left = this->left_;
- Temporary_statement* left_temp = NULL;
- if (left->var_expression() == NULL
- && left->temporary_reference_expression() == NULL)
- {
- left_temp = Statement::make_temporary(left->type(), NULL, loc);
- inserter->insert(left_temp);
- left = Expression::make_set_and_use_temporary(left_temp, left, loc);
- }
-
- Expression* right = this->right_;
- Temporary_statement* right_temp = NULL;
- if (right->var_expression() == NULL
- && right->temporary_reference_expression() == NULL)
- {
- right_temp = Statement::make_temporary(right->type(), NULL, loc);
- inserter->insert(right_temp);
- right = Expression::make_set_and_use_temporary(right_temp, right, loc);
- }
-
- Expression* ret = Expression::make_boolean(true, loc);
- const Struct_field_list* fields = st->fields();
- unsigned int field_index = 0;
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf, ++field_index)
- {
- if (Gogo::is_sink_name(pf->field_name()))
- continue;
-
- if (field_index > 0)
- {
- if (left_temp == NULL)
- left = left->copy();
- else
- left = Expression::make_temporary_reference(left_temp, loc);
- if (right_temp == NULL)
- right = right->copy();
- else
- right = Expression::make_temporary_reference(right_temp, loc);
- }
- Expression* f1 = Expression::make_field_reference(left, field_index,
- loc);
- Expression* f2 = Expression::make_field_reference(right, field_index,
- loc);
- Expression* cond = Expression::make_binary(OPERATOR_EQEQ, f1, f2, loc);
- ret = Expression::make_binary(OPERATOR_ANDAND, ret, cond, loc);
- }
-
- if (this->op_ == OPERATOR_NOTEQ)
- ret = Expression::make_unary(OPERATOR_NOT, ret, loc);
-
- return ret;
-}
-
-// Lower an array comparison.
-
-Expression*
-Binary_expression::lower_array_comparison(Gogo* gogo,
- Statement_inserter* inserter)
-{
- Array_type* at = this->left_->type()->array_type();
- Array_type* at2 = this->right_->type()->array_type();
- if (at2 == NULL)
- return this;
- if (at != at2 && !Type::are_identical(at, at2, false, NULL))
- return this;
- if (!Type::are_compatible_for_comparison(true, this->left_->type(),
- this->right_->type(), NULL))
- return this;
-
- // Call memcmp directly if possible. This may let the middle-end
- // optimize the call.
- if (at->compare_is_identity(gogo))
- return this->lower_compare_to_memcmp(gogo, inserter);
-
- // Call the array comparison function.
- Named_object* hash_fn;
- Named_object* equal_fn;
- at->type_functions(gogo, this->left_->type()->named_type(), NULL, NULL,
- &hash_fn, &equal_fn);
-
- Location loc = this->location();
-
- Expression* func = Expression::make_func_reference(equal_fn, NULL, loc);
-
- Expression_list* args = new Expression_list();
- args->push_back(this->operand_address(inserter, this->left_));
- args->push_back(this->operand_address(inserter, this->right_));
- args->push_back(Expression::make_type_info(at, TYPE_INFO_SIZE));
-
- Expression* ret = Expression::make_call(func, args, false, loc);
-
- if (this->op_ == OPERATOR_NOTEQ)
- ret = Expression::make_unary(OPERATOR_NOT, ret, loc);
-
- return ret;
-}
-
-// Lower a struct or array comparison to a call to memcmp.
-
-Expression*
-Binary_expression::lower_compare_to_memcmp(Gogo*, Statement_inserter* inserter)
-{
- Location loc = this->location();
-
- Expression* a1 = this->operand_address(inserter, this->left_);
- Expression* a2 = this->operand_address(inserter, this->right_);
- Expression* len = Expression::make_type_info(this->left_->type(),
- TYPE_INFO_SIZE);
-
- Expression* call = Runtime::make_call(Runtime::MEMCMP, loc, 3, a1, a2, len);
-
- mpz_t zval;
- mpz_init_set_ui(zval, 0);
- Expression* zero = Expression::make_integer(&zval, NULL, loc);
- mpz_clear(zval);
-
- return Expression::make_binary(this->op_, call, zero, loc);
-}
-
-// Return the address of EXPR, cast to unsafe.Pointer.
-
-Expression*
-Binary_expression::operand_address(Statement_inserter* inserter,
- Expression* expr)
-{
- Location loc = this->location();
-
- if (!expr->is_addressable())
- {
- Temporary_statement* temp = Statement::make_temporary(expr->type(), NULL,
- loc);
- inserter->insert(temp);
- expr = Expression::make_set_and_use_temporary(temp, expr, loc);
- }
- expr = Expression::make_unary(OPERATOR_AND, expr, loc);
- static_cast<Unary_expression*>(expr)->set_does_not_escape();
- Type* void_type = Type::make_void_type();
- Type* unsafe_pointer_type = Type::make_pointer_type(void_type);
- return Expression::make_cast(unsafe_pointer_type, expr, loc);
-}
-
-// Return the numeric constant value, if it has one.
-
-bool
-Binary_expression::do_numeric_constant_value(Numeric_constant* nc) const
-{
- Numeric_constant left_nc;
- if (!this->left_->numeric_constant_value(&left_nc))
- return false;
- Numeric_constant right_nc;
- if (!this->right_->numeric_constant_value(&right_nc))
- return false;
- return Binary_expression::eval_constant(this->op_, &left_nc, &right_nc,
- this->location(), nc);
-}
-
-// Note that the value is being discarded.
-
-bool
-Binary_expression::do_discarding_value()
-{
- if (this->op_ == OPERATOR_OROR || this->op_ == OPERATOR_ANDAND)
- return this->right_->discarding_value();
- else
- {
- this->unused_value_error();
- return false;
- }
-}
-
-// Get type.
-
-Type*
-Binary_expression::do_type()
-{
- if (this->classification() == EXPRESSION_ERROR)
- return Type::make_error_type();
-
- switch (this->op_)
- {
- case OPERATOR_EQEQ:
- case OPERATOR_NOTEQ:
- case OPERATOR_LT:
- case OPERATOR_LE:
- case OPERATOR_GT:
- case OPERATOR_GE:
- if (this->type_ == NULL)
- this->type_ = Type::make_boolean_type();
- return this->type_;
-
- case OPERATOR_PLUS:
- case OPERATOR_MINUS:
- case OPERATOR_OR:
- case OPERATOR_XOR:
- case OPERATOR_MULT:
- case OPERATOR_DIV:
- case OPERATOR_MOD:
- case OPERATOR_AND:
- case OPERATOR_BITCLEAR:
- case OPERATOR_OROR:
- case OPERATOR_ANDAND:
- {
- Type* type;
- if (!Binary_expression::operation_type(this->op_,
- this->left_->type(),
- this->right_->type(),
- &type))
- return Type::make_error_type();
- return type;
- }
-
- case OPERATOR_LSHIFT:
- case OPERATOR_RSHIFT:
- return this->left_->type();
-
- default:
- go_unreachable();
- }
-}
-
-// Set type for a binary expression.
-
-void
-Binary_expression::do_determine_type(const Type_context* context)
-{
- Type* tleft = this->left_->type();
- Type* tright = this->right_->type();
-
- // Both sides should have the same type, except for the shift
- // operations. For a comparison, we should ignore the incoming
- // type.
-
- bool is_shift_op = (this->op_ == OPERATOR_LSHIFT
- || this->op_ == OPERATOR_RSHIFT);
-
- bool is_comparison = (this->op_ == OPERATOR_EQEQ
- || this->op_ == OPERATOR_NOTEQ
- || this->op_ == OPERATOR_LT
- || this->op_ == OPERATOR_LE
- || this->op_ == OPERATOR_GT
- || this->op_ == OPERATOR_GE);
-
- Type_context subcontext(*context);
-
- if (is_comparison)
- {
- // In a comparison, the context does not determine the types of
- // the operands.
- subcontext.type = NULL;
- }
-
- // Set the context for the left hand operand.
- if (is_shift_op)
- {
- // The right hand operand of a shift plays no role in
- // determining the type of the left hand operand.
- }
- else if (!tleft->is_abstract())
- subcontext.type = tleft;
- else if (!tright->is_abstract())
- subcontext.type = tright;
- else if (subcontext.type == NULL)
- {
- if ((tleft->integer_type() != NULL && tright->integer_type() != NULL)
- || (tleft->float_type() != NULL && tright->float_type() != NULL)
- || (tleft->complex_type() != NULL && tright->complex_type() != NULL))
- {
- // Both sides have an abstract integer, abstract float, or
- // abstract complex type. Just let CONTEXT determine
- // whether they may remain abstract or not.
- }
- else if (tleft->complex_type() != NULL)
- subcontext.type = tleft;
- else if (tright->complex_type() != NULL)
- subcontext.type = tright;
- else if (tleft->float_type() != NULL)
- subcontext.type = tleft;
- else if (tright->float_type() != NULL)
- subcontext.type = tright;
- else
- subcontext.type = tleft;
-
- if (subcontext.type != NULL && !context->may_be_abstract)
- subcontext.type = subcontext.type->make_non_abstract_type();
- }
-
- this->left_->determine_type(&subcontext);
-
- if (is_shift_op)
- {
- // We may have inherited an unusable type for the shift operand.
- // Give a useful error if that happened.
- if (tleft->is_abstract()
- && subcontext.type != NULL
- && !subcontext.may_be_abstract
- && subcontext.type->integer_type() == NULL)
- this->report_error(("invalid context-determined non-integer type "
- "for left operand of shift"));
-
- // The context for the right hand operand is the same as for the
- // left hand operand, except for a shift operator.
- subcontext.type = Type::lookup_integer_type("uint");
- subcontext.may_be_abstract = false;
- }
-
- this->right_->determine_type(&subcontext);
-
- if (is_comparison)
- {
- if (this->type_ != NULL && !this->type_->is_abstract())
- ;
- else if (context->type != NULL && context->type->is_boolean_type())
- this->type_ = context->type;
- else if (!context->may_be_abstract)
- this->type_ = Type::lookup_bool_type();
- }
-}
-
-// Report an error if the binary operator OP does not support TYPE.
-// OTYPE is the type of the other operand. Return whether the
-// operation is OK. This should not be used for shift.
-
-bool
-Binary_expression::check_operator_type(Operator op, Type* type, Type* otype,
- Location location)
-{
- switch (op)
- {
- case OPERATOR_OROR:
- case OPERATOR_ANDAND:
- if (!type->is_boolean_type())
- {
- error_at(location, "expected boolean type");
- return false;
- }
- break;
-
- case OPERATOR_EQEQ:
- case OPERATOR_NOTEQ:
- {
- std::string reason;
- if (!Type::are_compatible_for_comparison(true, type, otype, &reason))
- {
- error_at(location, "%s", reason.c_str());
- return false;
- }
- }
- break;
-
- case OPERATOR_LT:
- case OPERATOR_LE:
- case OPERATOR_GT:
- case OPERATOR_GE:
- {
- std::string reason;
- if (!Type::are_compatible_for_comparison(false, type, otype, &reason))
- {
- error_at(location, "%s", reason.c_str());
- return false;
- }
- }
- break;
-
- case OPERATOR_PLUS:
- case OPERATOR_PLUSEQ:
- if (type->integer_type() == NULL
- && type->float_type() == NULL
- && type->complex_type() == NULL
- && !type->is_string_type())
- {
- error_at(location,
- "expected integer, floating, complex, or string type");
- return false;
- }
- break;
-
- case OPERATOR_MINUS:
- case OPERATOR_MINUSEQ:
- case OPERATOR_MULT:
- case OPERATOR_MULTEQ:
- case OPERATOR_DIV:
- case OPERATOR_DIVEQ:
- if (type->integer_type() == NULL
- && type->float_type() == NULL
- && type->complex_type() == NULL)
- {
- error_at(location, "expected integer, floating, or complex type");
- return false;
- }
- break;
-
- case OPERATOR_MOD:
- case OPERATOR_MODEQ:
- case OPERATOR_OR:
- case OPERATOR_OREQ:
- case OPERATOR_AND:
- case OPERATOR_ANDEQ:
- case OPERATOR_XOR:
- case OPERATOR_XOREQ:
- case OPERATOR_BITCLEAR:
- case OPERATOR_BITCLEAREQ:
- if (type->integer_type() == NULL)
- {
- error_at(location, "expected integer type");
- return false;
- }
- break;
-
- default:
- go_unreachable();
- }
-
- return true;
-}
-
-// Check types.
-
-void
-Binary_expression::do_check_types(Gogo*)
-{
- if (this->classification() == EXPRESSION_ERROR)
- return;
-
- Type* left_type = this->left_->type();
- Type* right_type = this->right_->type();
- if (left_type->is_error() || right_type->is_error())
- {
- this->set_is_error();
- return;
- }
-
- if (this->op_ == OPERATOR_EQEQ
- || this->op_ == OPERATOR_NOTEQ
- || this->op_ == OPERATOR_LT
- || this->op_ == OPERATOR_LE
- || this->op_ == OPERATOR_GT
- || this->op_ == OPERATOR_GE)
- {
- if (left_type->is_nil_type() && right_type->is_nil_type())
- {
- this->report_error(_("invalid comparison of nil with nil"));
- return;
- }
- if (!Type::are_assignable(left_type, right_type, NULL)
- && !Type::are_assignable(right_type, left_type, NULL))
- {
- this->report_error(_("incompatible types in binary expression"));
- return;
- }
- if (!Binary_expression::check_operator_type(this->op_, left_type,
- right_type,
- this->location())
- || !Binary_expression::check_operator_type(this->op_, right_type,
- left_type,
- this->location()))
- {
- this->set_is_error();
- return;
- }
- }
- else if (this->op_ != OPERATOR_LSHIFT && this->op_ != OPERATOR_RSHIFT)
- {
- if (!Type::are_compatible_for_binop(left_type, right_type))
- {
- this->report_error(_("incompatible types in binary expression"));
- return;
- }
- if (!Binary_expression::check_operator_type(this->op_, left_type,
- right_type,
- this->location()))
- {
- this->set_is_error();
- return;
- }
- }
- else
- {
- if (left_type->integer_type() == NULL)
- this->report_error(_("shift of non-integer operand"));
-
- if (!right_type->is_abstract()
- && (right_type->integer_type() == NULL
- || !right_type->integer_type()->is_unsigned()))
- this->report_error(_("shift count not unsigned integer"));
- else
- {
- Numeric_constant nc;
- if (this->right_->numeric_constant_value(&nc))
- {
- mpz_t val;
- if (!nc.to_int(&val))
- this->report_error(_("shift count not unsigned integer"));
- else
- {
- if (mpz_sgn(val) < 0)
- {
- this->report_error(_("negative shift count"));
- mpz_set_ui(val, 0);
- Location rloc = this->right_->location();
- this->right_ = Expression::make_integer(&val, right_type,
- rloc);
- }
- mpz_clear(val);
- }
- }
- }
- }
-}
-
-// Get a tree for a binary expression.
-
-tree
-Binary_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
-
- tree left = this->left_->get_tree(context);
- tree right = this->right_->get_tree(context);
-
- if (left == error_mark_node || right == error_mark_node)
- return error_mark_node;
-
- enum tree_code code;
- bool use_left_type = true;
- bool is_shift_op = false;
- bool is_idiv_op = false;
- switch (this->op_)
- {
- case OPERATOR_EQEQ:
- case OPERATOR_NOTEQ:
- case OPERATOR_LT:
- case OPERATOR_LE:
- case OPERATOR_GT:
- case OPERATOR_GE:
- return Expression::comparison_tree(context, this->type_, this->op_,
- this->left_->type(), left,
- this->right_->type(), right,
- this->location());
-
- case OPERATOR_OROR:
- code = TRUTH_ORIF_EXPR;
- use_left_type = false;
- break;
- case OPERATOR_ANDAND:
- code = TRUTH_ANDIF_EXPR;
- use_left_type = false;
- break;
- case OPERATOR_PLUS:
- code = PLUS_EXPR;
- break;
- case OPERATOR_MINUS:
- code = MINUS_EXPR;
- break;
- case OPERATOR_OR:
- code = BIT_IOR_EXPR;
- break;
- case OPERATOR_XOR:
- code = BIT_XOR_EXPR;
- break;
- case OPERATOR_MULT:
- code = MULT_EXPR;
- break;
- case OPERATOR_DIV:
- {
- Type *t = this->left_->type();
- if (t->float_type() != NULL || t->complex_type() != NULL)
- code = RDIV_EXPR;
- else
- {
- code = TRUNC_DIV_EXPR;
- is_idiv_op = true;
- }
- }
- break;
- case OPERATOR_MOD:
- code = TRUNC_MOD_EXPR;
- is_idiv_op = true;
- break;
- case OPERATOR_LSHIFT:
- code = LSHIFT_EXPR;
- is_shift_op = true;
- break;
- case OPERATOR_RSHIFT:
- code = RSHIFT_EXPR;
- is_shift_op = true;
- break;
- case OPERATOR_AND:
- code = BIT_AND_EXPR;
- break;
- case OPERATOR_BITCLEAR:
- right = fold_build1(BIT_NOT_EXPR, TREE_TYPE(right), right);
- code = BIT_AND_EXPR;
- break;
- default:
- go_unreachable();
- }
-
- location_t gccloc = this->location().gcc_location();
- tree type = use_left_type ? TREE_TYPE(left) : TREE_TYPE(right);
-
- if (this->left_->type()->is_string_type())
- {
- go_assert(this->op_ == OPERATOR_PLUS);
- Type* st = Type::make_string_type();
- tree string_type = type_to_tree(st->get_backend(gogo));
- static tree string_plus_decl;
- return Gogo::call_builtin(&string_plus_decl,
- this->location(),
- "__go_string_plus",
- 2,
- string_type,
- string_type,
- left,
- string_type,
- right);
- }
-
- tree compute_type = excess_precision_type(type);
- if (compute_type != NULL_TREE)
- {
- left = ::convert(compute_type, left);
- right = ::convert(compute_type, right);
- }
-
- tree eval_saved = NULL_TREE;
- if (is_shift_op
- || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow)))
- {
- // Make sure the values are evaluated.
- if (!DECL_P(left))
- {
- left = save_expr(left);
- eval_saved = left;
- }
- if (!DECL_P(right))
- {
- right = save_expr(right);
- if (eval_saved == NULL_TREE)
- eval_saved = right;
- else
- eval_saved = fold_build2_loc(gccloc, COMPOUND_EXPR,
- void_type_node, eval_saved, right);
- }
- }
-
- tree ret = fold_build2_loc(gccloc, code,
- compute_type != NULL_TREE ? compute_type : type,
- left, right);
-
- if (compute_type != NULL_TREE)
- ret = ::convert(type, ret);
-
- // In Go, a shift larger than the size of the type is well-defined.
- // This is not true in GENERIC, so we need to insert a conditional.
- if (is_shift_op)
- {
- go_assert(INTEGRAL_TYPE_P(TREE_TYPE(left)));
- go_assert(this->left_->type()->integer_type() != NULL);
- int bits = TYPE_PRECISION(TREE_TYPE(left));
-
- tree compare = fold_build2(LT_EXPR, boolean_type_node, right,
- build_int_cst_type(TREE_TYPE(right), bits));
-
- tree overflow_result = fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_zero_node);
- if (this->op_ == OPERATOR_RSHIFT
- && !this->left_->type()->integer_type()->is_unsigned())
- {
- tree neg =
- fold_build2_loc(gccloc, LT_EXPR, boolean_type_node,
- left,
- fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_zero_node));
- tree neg_one =
- fold_build2_loc(gccloc, MINUS_EXPR, TREE_TYPE(left),
- fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_zero_node),
- fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_one_node));
- overflow_result =
- fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left),
- neg, neg_one, overflow_result);
- }
-
- ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left),
- compare, ret, overflow_result);
-
- if (eval_saved != NULL_TREE)
- ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
- eval_saved, ret);
- }
-
- // Add checks for division by zero and division overflow as needed.
- if (is_idiv_op)
- {
- if (go_check_divide_zero)
- {
- // right == 0
- tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
- right,
- fold_convert_loc(gccloc,
- TREE_TYPE(right),
- integer_zero_node));
-
- // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO), 0
- int errcode = RUNTIME_ERROR_DIVISION_BY_ZERO;
- tree panic = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
- gogo->runtime_error(errcode,
- this->location()),
- fold_convert_loc(gccloc, TREE_TYPE(ret),
- integer_zero_node));
-
- // right == 0 ? (__go_runtime_error(...), 0) : ret
- ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- check, panic, ret);
- }
-
- if (go_check_divide_overflow)
- {
- // right == -1
- // FIXME: It would be nice to say that this test is expected
- // to return false.
- tree m1 = integer_minus_one_node;
- tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
- right,
- fold_convert_loc(gccloc,
- TREE_TYPE(right),
- m1));
-
- tree overflow;
- if (TYPE_UNSIGNED(TREE_TYPE(ret)))
- {
- // An unsigned -1 is the largest possible number, so
- // dividing is always 1 or 0.
- tree cmp = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
- left, right);
- if (this->op_ == OPERATOR_DIV)
- overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- cmp,
- fold_convert_loc(gccloc,
- TREE_TYPE(ret),
- integer_one_node),
- fold_convert_loc(gccloc,
- TREE_TYPE(ret),
- integer_zero_node));
- else
- overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- cmp,
- fold_convert_loc(gccloc,
- TREE_TYPE(ret),
- integer_zero_node),
- left);
- }
- else
- {
- // Computing left / -1 is the same as computing - left,
- // which does not overflow since Go sets -fwrapv.
- if (this->op_ == OPERATOR_DIV)
- overflow = fold_build1_loc(gccloc, NEGATE_EXPR, TREE_TYPE(left),
- left);
- else
- overflow = integer_zero_node;
- }
- overflow = fold_convert_loc(gccloc, TREE_TYPE(ret), overflow);
-
- // right == -1 ? - left : ret
- ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- check, overflow, ret);
- }
-
- if (eval_saved != NULL_TREE)
- ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
- eval_saved, ret);
- }
-
- return ret;
-}
-
-// Export a binary expression.
-
-void
-Binary_expression::do_export(Export* exp) const
-{
- exp->write_c_string("(");
- this->left_->export_expression(exp);
- switch (this->op_)
- {
- case OPERATOR_OROR:
- exp->write_c_string(" || ");
- break;
- case OPERATOR_ANDAND:
- exp->write_c_string(" && ");
- break;
- case OPERATOR_EQEQ:
- exp->write_c_string(" == ");
- break;
- case OPERATOR_NOTEQ:
- exp->write_c_string(" != ");
- break;
- case OPERATOR_LT:
- exp->write_c_string(" < ");
- break;
- case OPERATOR_LE:
- exp->write_c_string(" <= ");
- break;
- case OPERATOR_GT:
- exp->write_c_string(" > ");
- break;
- case OPERATOR_GE:
- exp->write_c_string(" >= ");
- break;
- case OPERATOR_PLUS:
- exp->write_c_string(" + ");
- break;
- case OPERATOR_MINUS:
- exp->write_c_string(" - ");
- break;
- case OPERATOR_OR:
- exp->write_c_string(" | ");
- break;
- case OPERATOR_XOR:
- exp->write_c_string(" ^ ");
- break;
- case OPERATOR_MULT:
- exp->write_c_string(" * ");
- break;
- case OPERATOR_DIV:
- exp->write_c_string(" / ");
- break;
- case OPERATOR_MOD:
- exp->write_c_string(" % ");
- break;
- case OPERATOR_LSHIFT:
- exp->write_c_string(" << ");
- break;
- case OPERATOR_RSHIFT:
- exp->write_c_string(" >> ");
- break;
- case OPERATOR_AND:
- exp->write_c_string(" & ");
- break;
- case OPERATOR_BITCLEAR:
- exp->write_c_string(" &^ ");
- break;
- default:
- go_unreachable();
- }
- this->right_->export_expression(exp);
- exp->write_c_string(")");
-}
-
-// Import a binary expression.
-
-Expression*
-Binary_expression::do_import(Import* imp)
-{
- imp->require_c_string("(");
-
- Expression* left = Expression::import_expression(imp);
-
- Operator op;
- if (imp->match_c_string(" || "))
- {
- op = OPERATOR_OROR;
- imp->advance(4);
- }
- else if (imp->match_c_string(" && "))
- {
- op = OPERATOR_ANDAND;
- imp->advance(4);
- }
- else if (imp->match_c_string(" == "))
- {
- op = OPERATOR_EQEQ;
- imp->advance(4);
- }
- else if (imp->match_c_string(" != "))
- {
- op = OPERATOR_NOTEQ;
- imp->advance(4);
- }
- else if (imp->match_c_string(" < "))
- {
- op = OPERATOR_LT;
- imp->advance(3);
- }
- else if (imp->match_c_string(" <= "))
- {
- op = OPERATOR_LE;
- imp->advance(4);
- }
- else if (imp->match_c_string(" > "))
- {
- op = OPERATOR_GT;
- imp->advance(3);
- }
- else if (imp->match_c_string(" >= "))
- {
- op = OPERATOR_GE;
- imp->advance(4);
- }
- else if (imp->match_c_string(" + "))
- {
- op = OPERATOR_PLUS;
- imp->advance(3);
- }
- else if (imp->match_c_string(" - "))
- {
- op = OPERATOR_MINUS;
- imp->advance(3);
- }
- else if (imp->match_c_string(" | "))
- {
- op = OPERATOR_OR;
- imp->advance(3);
- }
- else if (imp->match_c_string(" ^ "))
- {
- op = OPERATOR_XOR;
- imp->advance(3);
- }
- else if (imp->match_c_string(" * "))
- {
- op = OPERATOR_MULT;
- imp->advance(3);
- }
- else if (imp->match_c_string(" / "))
- {
- op = OPERATOR_DIV;
- imp->advance(3);
- }
- else if (imp->match_c_string(" % "))
- {
- op = OPERATOR_MOD;
- imp->advance(3);
- }
- else if (imp->match_c_string(" << "))
- {
- op = OPERATOR_LSHIFT;
- imp->advance(4);
- }
- else if (imp->match_c_string(" >> "))
- {
- op = OPERATOR_RSHIFT;
- imp->advance(4);
- }
- else if (imp->match_c_string(" & "))
- {
- op = OPERATOR_AND;
- imp->advance(3);
- }
- else if (imp->match_c_string(" &^ "))
- {
- op = OPERATOR_BITCLEAR;
- imp->advance(4);
- }
- else
- {
- error_at(imp->location(), "unrecognized binary operator");
- return Expression::make_error(imp->location());
- }
-
- Expression* right = Expression::import_expression(imp);
-
- imp->require_c_string(")");
-
- return Expression::make_binary(op, left, right, imp->location());
-}
-
-// Dump ast representation of a binary expression.
-
-void
-Binary_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << "(";
- ast_dump_context->dump_expression(this->left_);
- ast_dump_context->ostream() << " ";
- ast_dump_context->dump_operator(this->op_);
- ast_dump_context->ostream() << " ";
- ast_dump_context->dump_expression(this->right_);
- ast_dump_context->ostream() << ") ";
-}
-
-// Make a binary expression.
-
-Expression*
-Expression::make_binary(Operator op, Expression* left, Expression* right,
- Location location)
-{
- return new Binary_expression(op, left, right, location);
-}
-
-// Implement a comparison.
-
-tree
-Expression::comparison_tree(Translate_context* context, Type* result_type,
- Operator op, Type* left_type, tree left_tree,
- Type* right_type, tree right_tree,
- Location location)
-{
- Type* int_type = Type::lookup_integer_type("int");
- tree int_type_tree = type_to_tree(int_type->get_backend(context->gogo()));
-
- enum tree_code code;
- switch (op)
- {
- case OPERATOR_EQEQ:
- code = EQ_EXPR;
- break;
- case OPERATOR_NOTEQ:
- code = NE_EXPR;
- break;
- case OPERATOR_LT:
- code = LT_EXPR;
- break;
- case OPERATOR_LE:
- code = LE_EXPR;
- break;
- case OPERATOR_GT:
- code = GT_EXPR;
- break;
- case OPERATOR_GE:
- code = GE_EXPR;
- break;
- default:
- go_unreachable();
- }
-
- if (left_type->is_string_type() && right_type->is_string_type())
- {
- Type* st = Type::make_string_type();
- tree string_type = type_to_tree(st->get_backend(context->gogo()));
- static tree string_compare_decl;
- left_tree = Gogo::call_builtin(&string_compare_decl,
- location,
- "__go_strcmp",
- 2,
- int_type_tree,
- string_type,
- left_tree,
- string_type,
- right_tree);
- right_tree = build_int_cst_type(int_type_tree, 0);
- }
- else if ((left_type->interface_type() != NULL
- && right_type->interface_type() == NULL
- && !right_type->is_nil_type())
- || (left_type->interface_type() == NULL
- && !left_type->is_nil_type()
- && right_type->interface_type() != NULL))
- {
- // Comparing an interface value to a non-interface value.
- if (left_type->interface_type() == NULL)
- {
- std::swap(left_type, right_type);
- std::swap(left_tree, right_tree);
- }
-
- // The right operand is not an interface. We need to take its
- // address if it is not a pointer.
- tree make_tmp;
- tree arg;
- if (right_type->points_to() != NULL)
- {
- make_tmp = NULL_TREE;
- arg = right_tree;
- }
- else if (TREE_ADDRESSABLE(TREE_TYPE(right_tree))
- || (TREE_CODE(right_tree) != CONST_DECL
- && DECL_P(right_tree)))
- {
- make_tmp = NULL_TREE;
- arg = build_fold_addr_expr_loc(location.gcc_location(), right_tree);
- if (DECL_P(right_tree))
- TREE_ADDRESSABLE(right_tree) = 1;
- }
- else
- {
- tree tmp = create_tmp_var(TREE_TYPE(right_tree),
- get_name(right_tree));
- DECL_IGNORED_P(tmp) = 0;
- DECL_INITIAL(tmp) = right_tree;
- TREE_ADDRESSABLE(tmp) = 1;
- make_tmp = build1(DECL_EXPR, void_type_node, tmp);
- SET_EXPR_LOCATION(make_tmp, location.gcc_location());
- arg = build_fold_addr_expr_loc(location.gcc_location(), tmp);
- }
- arg = fold_convert_loc(location.gcc_location(), ptr_type_node, arg);
-
- tree descriptor = right_type->type_descriptor_pointer(context->gogo(),
- location);
-
- if (left_type->interface_type()->is_empty())
- {
- static tree empty_interface_value_compare_decl;
- left_tree = Gogo::call_builtin(&empty_interface_value_compare_decl,
- location,
- "__go_empty_interface_value_compare",
- 3,
- int_type_tree,
- TREE_TYPE(left_tree),
- left_tree,
- TREE_TYPE(descriptor),
- 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;
- }
- else
- {
- static tree interface_value_compare_decl;
- left_tree = Gogo::call_builtin(&interface_value_compare_decl,
- location,
- "__go_interface_value_compare",
- 3,
- int_type_tree,
- TREE_TYPE(left_tree),
- left_tree,
- TREE_TYPE(descriptor),
- 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;
- }
- right_tree = build_int_cst_type(int_type_tree, 0);
-
- if (make_tmp != NULL_TREE)
- left_tree = build2(COMPOUND_EXPR, TREE_TYPE(left_tree), make_tmp,
- left_tree);
- }
- else if (left_type->interface_type() != NULL
- && right_type->interface_type() != NULL)
- {
- if (left_type->interface_type()->is_empty()
- && right_type->interface_type()->is_empty())
- {
- static tree empty_interface_compare_decl;
- left_tree = Gogo::call_builtin(&empty_interface_compare_decl,
- location,
- "__go_empty_interface_compare",
- 2,
- int_type_tree,
- TREE_TYPE(left_tree),
- 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;
- }
- else if (!left_type->interface_type()->is_empty()
- && !right_type->interface_type()->is_empty())
- {
- static tree interface_compare_decl;
- left_tree = Gogo::call_builtin(&interface_compare_decl,
- location,
- "__go_interface_compare",
- 2,
- int_type_tree,
- TREE_TYPE(left_tree),
- 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;
- }
- else
- {
- if (left_type->interface_type()->is_empty())
- {
- go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ);
- std::swap(left_type, right_type);
- std::swap(left_tree, right_tree);
- }
- go_assert(!left_type->interface_type()->is_empty());
- go_assert(right_type->interface_type()->is_empty());
- static tree interface_empty_compare_decl;
- left_tree = Gogo::call_builtin(&interface_empty_compare_decl,
- location,
- "__go_interface_empty_compare",
- 2,
- int_type_tree,
- TREE_TYPE(left_tree),
- 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_empty_compare_decl) = 0;
- }
-
- right_tree = build_int_cst_type(int_type_tree, 0);
- }
-
- if (left_type->is_nil_type()
- && (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ))
- {
- std::swap(left_type, right_type);
- std::swap(left_tree, right_tree);
- }
-
- if (right_type->is_nil_type())
- {
- if (left_type->array_type() != NULL
- && left_type->array_type()->length() == NULL)
- {
- Array_type* at = left_type->array_type();
- left_tree = at->value_pointer_tree(context->gogo(), left_tree);
- right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
- }
- else if (left_type->interface_type() != NULL)
- {
- // An interface is nil if the first field is nil.
- tree left_type_tree = TREE_TYPE(left_tree);
- go_assert(TREE_CODE(left_type_tree) == RECORD_TYPE);
- tree field = TYPE_FIELDS(left_type_tree);
- left_tree = build3(COMPONENT_REF, TREE_TYPE(field), left_tree,
- field, NULL_TREE);
- right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
- }
- else
- {
- go_assert(POINTER_TYPE_P(TREE_TYPE(left_tree)));
- right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
- }
- }
-
- if (left_tree == error_mark_node || right_tree == error_mark_node)
- return error_mark_node;
-
- tree result_type_tree;
- if (result_type == NULL)
- result_type_tree = boolean_type_node;
- else
- result_type_tree = type_to_tree(result_type->get_backend(context->gogo()));
-
- tree ret = fold_build2(code, result_type_tree, left_tree, right_tree);
- if (CAN_HAVE_LOCATION_P(ret))
- SET_EXPR_LOCATION(ret, location.gcc_location());
- return ret;
-}
-
-// Class Bound_method_expression.
-
-// Traversal.
-
-int
-Bound_method_expression::do_traverse(Traverse* traverse)
-{
- return Expression::traverse(&this->expr_, traverse);
-}
-
-// Return the type of a bound method expression. The type of this
-// object is really the type of the method with no receiver. We
-// should be able to get away with just returning the type of the
-// method.
-
-Type*
-Bound_method_expression::do_type()
-{
- if (this->method_->is_function())
- return this->method_->func_value()->type();
- else if (this->method_->is_function_declaration())
- return this->method_->func_declaration_value()->type();
- else
- return Type::make_error_type();
-}
-
-// Determine the types of a method expression.
-
-void
-Bound_method_expression::do_determine_type(const Type_context*)
-{
- Function_type* fntype = this->type()->function_type();
- if (fntype == NULL || !fntype->is_method())
- this->expr_->determine_type_no_context();
- else
- {
- Type_context subcontext(fntype->receiver()->type(), false);
- this->expr_->determine_type(&subcontext);
- }
-}
-
-// Check the types of a method expression.
-
-void
-Bound_method_expression::do_check_types(Gogo*)
-{
- if (!this->method_->is_function()
- && !this->method_->is_function_declaration())
- this->report_error(_("object is not a method"));
- else
- {
- Type* rtype = this->type()->function_type()->receiver()->type()->deref();
- Type* etype = (this->expr_type_ != NULL
- ? this->expr_type_
- : this->expr_->type());
- etype = etype->deref();
- if (!Type::are_identical(rtype, etype, true, NULL))
- this->report_error(_("method type does not match object type"));
- }
-}
-
-// Get the tree for a method expression. There is no standard tree
-// representation for this. The only places it may currently be used
-// are in a Call_expression or a Go_statement, which will take it
-// apart directly. So this has nothing to do at present.
-
-tree
-Bound_method_expression::do_get_tree(Translate_context*)
-{
- error_at(this->location(), "reference to method other than calling it");
- return error_mark_node;
-}
-
-// Dump ast representation of a bound method expression.
-
-void
-Bound_method_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
- const
-{
- if (this->expr_type_ != NULL)
- ast_dump_context->ostream() << "(";
- ast_dump_context->dump_expression(this->expr_);
- if (this->expr_type_ != NULL)
- {
- ast_dump_context->ostream() << ":";
- ast_dump_context->dump_type(this->expr_type_);
- ast_dump_context->ostream() << ")";
- }
-
- ast_dump_context->ostream() << "." << this->method_->name();
-}
-
-// Make a method expression.
-
-Bound_method_expression*
-Expression::make_bound_method(Expression* expr, Named_object* method,
- Location location)
-{
- return new Bound_method_expression(expr, method, location);
-}
-
-// Class Builtin_call_expression. This is used for a call to a
-// builtin function.
-
-class Builtin_call_expression : public Call_expression
-{
- public:
- Builtin_call_expression(Gogo* gogo, Expression* fn, Expression_list* args,
- bool is_varargs, Location location);
-
- protected:
- // This overrides Call_expression::do_lower.
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- bool
- do_is_constant() const;
-
- bool
- do_numeric_constant_value(Numeric_constant*) const;
-
- bool
- do_discarding_value();
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return new Builtin_call_expression(this->gogo_, this->fn()->copy(),
- this->args()->copy(),
- this->is_varargs(),
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_export(Export*) const;
-
- virtual bool
- do_is_recover_call() const;
-
- virtual void
- do_set_recover_arg(Expression*);
-
- private:
- // The builtin functions.
- enum Builtin_function_code
- {
- BUILTIN_INVALID,
-
- // Predeclared builtin functions.
- BUILTIN_APPEND,
- BUILTIN_CAP,
- BUILTIN_CLOSE,
- BUILTIN_COMPLEX,
- BUILTIN_COPY,
- BUILTIN_DELETE,
- BUILTIN_IMAG,
- BUILTIN_LEN,
- BUILTIN_MAKE,
- BUILTIN_NEW,
- BUILTIN_PANIC,
- BUILTIN_PRINT,
- BUILTIN_PRINTLN,
- BUILTIN_REAL,
- BUILTIN_RECOVER,
-
- // Builtin functions from the unsafe package.
- BUILTIN_ALIGNOF,
- BUILTIN_OFFSETOF,
- BUILTIN_SIZEOF
- };
-
- Expression*
- one_arg() const;
-
- bool
- check_one_arg();
-
- static Type*
- real_imag_type(Type*);
-
- static Type*
- complex_type(Type*);
-
- Expression*
- lower_make();
-
- bool
- check_int_value(Expression*, bool is_length);
-
- // A pointer back to the general IR structure. This avoids a global
- // variable, or passing it around everywhere.
- Gogo* gogo_;
- // The builtin function being called.
- Builtin_function_code code_;
- // Used to stop endless loops when the length of an array uses len
- // or cap of the array itself.
- mutable bool seen_;
-};
-
-Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
- Expression* fn,
- Expression_list* args,
- bool is_varargs,
- Location location)
- : Call_expression(fn, args, is_varargs, location),
- gogo_(gogo), code_(BUILTIN_INVALID), seen_(false)
-{
- Func_expression* fnexp = this->fn()->func_expression();
- go_assert(fnexp != NULL);
- const std::string& name(fnexp->named_object()->name());
- if (name == "append")
- this->code_ = BUILTIN_APPEND;
- else if (name == "cap")
- this->code_ = BUILTIN_CAP;
- else if (name == "close")
- this->code_ = BUILTIN_CLOSE;
- else if (name == "complex")
- this->code_ = BUILTIN_COMPLEX;
- else if (name == "copy")
- this->code_ = BUILTIN_COPY;
- else if (name == "delete")
- this->code_ = BUILTIN_DELETE;
- else if (name == "imag")
- this->code_ = BUILTIN_IMAG;
- else if (name == "len")
- this->code_ = BUILTIN_LEN;
- else if (name == "make")
- this->code_ = BUILTIN_MAKE;
- else if (name == "new")
- this->code_ = BUILTIN_NEW;
- else if (name == "panic")
- this->code_ = BUILTIN_PANIC;
- else if (name == "print")
- this->code_ = BUILTIN_PRINT;
- else if (name == "println")
- this->code_ = BUILTIN_PRINTLN;
- else if (name == "real")
- this->code_ = BUILTIN_REAL;
- else if (name == "recover")
- this->code_ = BUILTIN_RECOVER;
- else if (name == "Alignof")
- this->code_ = BUILTIN_ALIGNOF;
- else if (name == "Offsetof")
- this->code_ = BUILTIN_OFFSETOF;
- else if (name == "Sizeof")
- this->code_ = BUILTIN_SIZEOF;
- else
- go_unreachable();
-}
-
-// Return whether this is a call to recover. This is a virtual
-// function called from the parent class.
-
-bool
-Builtin_call_expression::do_is_recover_call() const
-{
- if (this->classification() == EXPRESSION_ERROR)
- return false;
- return this->code_ == BUILTIN_RECOVER;
-}
-
-// Set the argument for a call to recover.
-
-void
-Builtin_call_expression::do_set_recover_arg(Expression* arg)
-{
- const Expression_list* args = this->args();
- go_assert(args == NULL || args->empty());
- Expression_list* new_args = new Expression_list();
- new_args->push_back(arg);
- this->set_args(new_args);
-}
-
-// Lower a builtin call expression. This turns new and make into
-// specific expressions. We also convert to a constant if we can.
-
-Expression*
-Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
- Statement_inserter* inserter, int)
-{
- if (this->classification() == EXPRESSION_ERROR)
- return this;
-
- Location loc = this->location();
-
- if (this->is_varargs() && this->code_ != BUILTIN_APPEND)
- {
- this->report_error(_("invalid use of %<...%> with builtin function"));
- return Expression::make_error(loc);
- }
-
- if (this->is_constant())
- {
- Numeric_constant nc;
- if (this->numeric_constant_value(&nc))
- return nc.expression(loc);
- }
-
- switch (this->code_)
- {
- default:
- break;
-
- case BUILTIN_NEW:
- {
- const Expression_list* args = this->args();
- if (args == NULL || args->size() < 1)
- this->report_error(_("not enough arguments"));
- else if (args->size() > 1)
- this->report_error(_("too many arguments"));
- else
- {
- Expression* arg = args->front();
- if (!arg->is_type_expression())
- {
- error_at(arg->location(), "expected type");
- this->set_is_error();
- }
- else
- return Expression::make_allocation(arg->type(), loc);
- }
- }
- break;
-
- case BUILTIN_MAKE:
- return this->lower_make();
-
- case BUILTIN_RECOVER:
- if (function != NULL)
- function->func_value()->set_calls_recover();
- else
- {
- // Calling recover outside of a function always returns the
- // nil empty interface.
- Type* eface = Type::make_empty_interface_type(loc);
- return Expression::make_cast(eface, Expression::make_nil(loc), loc);
- }
- break;
-
- case BUILTIN_APPEND:
- {
- // Lower the varargs.
- const Expression_list* args = this->args();
- if (args == NULL || args->empty())
- return this;
- Type* slice_type = args->front()->type();
- if (!slice_type->is_slice_type())
- {
- error_at(args->front()->location(), "argument 1 must be a slice");
- this->set_is_error();
- return this;
- }
- Type* element_type = slice_type->array_type()->element_type();
- this->lower_varargs(gogo, function, inserter,
- Type::make_array_type(element_type, NULL),
- 2);
- }
- break;
-
- case BUILTIN_DELETE:
- {
- // Lower to a runtime function call.
- const Expression_list* args = this->args();
- if (args == NULL || args->size() < 2)
- this->report_error(_("not enough arguments"));
- else if (args->size() > 2)
- this->report_error(_("too many arguments"));
- else if (args->front()->type()->map_type() == NULL)
- this->report_error(_("argument 1 must be a map"));
- else
- {
- // Since this function returns no value it must appear in
- // a statement by itself, so we don't have to worry about
- // order of evaluation of values around it. Evaluate the
- // map first to get order of evaluation right.
- Map_type* mt = args->front()->type()->map_type();
- Temporary_statement* map_temp =
- Statement::make_temporary(mt, args->front(), loc);
- inserter->insert(map_temp);
-
- Temporary_statement* key_temp =
- Statement::make_temporary(mt->key_type(), args->back(), loc);
- inserter->insert(key_temp);
-
- Expression* e1 = Expression::make_temporary_reference(map_temp,
- loc);
- Expression* e2 = Expression::make_temporary_reference(key_temp,
- loc);
- e2 = Expression::make_unary(OPERATOR_AND, e2, loc);
- return Runtime::make_call(Runtime::MAPDELETE, this->location(),
- 2, e1, e2);
- }
- }
- break;
- }
-
- return this;
-}
-
-// Lower a make expression.
-
-Expression*
-Builtin_call_expression::lower_make()
-{
- Location loc = this->location();
-
- const Expression_list* args = this->args();
- if (args == NULL || args->size() < 1)
- {
- this->report_error(_("not enough arguments"));
- return Expression::make_error(this->location());
- }
-
- Expression_list::const_iterator parg = args->begin();
-
- Expression* first_arg = *parg;
- if (!first_arg->is_type_expression())
- {
- error_at(first_arg->location(), "expected type");
- this->set_is_error();
- return Expression::make_error(this->location());
- }
- Type* type = first_arg->type();
-
- bool is_slice = false;
- bool is_map = false;
- bool is_chan = false;
- if (type->is_slice_type())
- is_slice = true;
- else if (type->map_type() != NULL)
- is_map = true;
- else if (type->channel_type() != NULL)
- is_chan = true;
- else
- {
- this->report_error(_("invalid type for make function"));
- return Expression::make_error(this->location());
- }
-
- bool have_big_args = false;
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
- int uintptr_bits = uintptr_type->integer_type()->bits();
-
- ++parg;
- Expression* len_arg;
- if (parg == args->end())
- {
- if (is_slice)
- {
- this->report_error(_("length required when allocating a slice"));
- return Expression::make_error(this->location());
- }
-
- mpz_t zval;
- mpz_init_set_ui(zval, 0);
- len_arg = Expression::make_integer(&zval, NULL, loc);
- mpz_clear(zval);
- }
- else
- {
- len_arg = *parg;
- if (!this->check_int_value(len_arg, true))
- return Expression::make_error(this->location());
- if (len_arg->type()->integer_type() != NULL
- && len_arg->type()->integer_type()->bits() > uintptr_bits)
- have_big_args = true;
- ++parg;
- }
-
- Expression* cap_arg = NULL;
- if (is_slice && parg != args->end())
- {
- cap_arg = *parg;
- if (!this->check_int_value(cap_arg, false))
- return Expression::make_error(this->location());
-
- Numeric_constant nclen;
- Numeric_constant nccap;
- unsigned long vlen;
- unsigned long vcap;
- if (len_arg->numeric_constant_value(&nclen)
- && cap_arg->numeric_constant_value(&nccap)
- && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID
- && nccap.to_unsigned_long(&vcap) == Numeric_constant::NC_UL_VALID
- && vlen > vcap)
- {
- this->report_error(_("len larger than cap"));
- return Expression::make_error(this->location());
- }
-
- if (cap_arg->type()->integer_type() != NULL
- && cap_arg->type()->integer_type()->bits() > uintptr_bits)
- have_big_args = true;
- ++parg;
- }
-
- if (parg != args->end())
- {
- this->report_error(_("too many arguments to make"));
- return Expression::make_error(this->location());
- }
-
- Location type_loc = first_arg->location();
- Expression* type_arg;
- if (is_slice || is_chan)
- type_arg = Expression::make_type_descriptor(type, type_loc);
- else if (is_map)
- type_arg = Expression::make_map_descriptor(type->map_type(), type_loc);
- else
- go_unreachable();
-
- Expression* call;
- if (is_slice)
- {
- if (cap_arg == NULL)
- call = Runtime::make_call((have_big_args
- ? Runtime::MAKESLICE1BIG
- : Runtime::MAKESLICE1),
- loc, 2, type_arg, len_arg);
- else
- call = Runtime::make_call((have_big_args
- ? Runtime::MAKESLICE2BIG
- : Runtime::MAKESLICE2),
- loc, 3, type_arg, len_arg, cap_arg);
- }
- else if (is_map)
- call = Runtime::make_call((have_big_args
- ? Runtime::MAKEMAPBIG
- : Runtime::MAKEMAP),
- loc, 2, type_arg, len_arg);
- else if (is_chan)
- call = Runtime::make_call((have_big_args
- ? Runtime::MAKECHANBIG
- : Runtime::MAKECHAN),
- loc, 2, type_arg, len_arg);
- else
- go_unreachable();
-
- return Expression::make_unsafe_cast(type, call, loc);
-}
-
-// Return whether an expression has an integer value. Report an error
-// if not. This is used when handling calls to the predeclared make
-// function.
-
-bool
-Builtin_call_expression::check_int_value(Expression* e, bool is_length)
-{
- Numeric_constant nc;
- if (e->numeric_constant_value(&nc))
- {
- unsigned long v;
- switch (nc.to_unsigned_long(&v))
- {
- case Numeric_constant::NC_UL_VALID:
- return true;
- case Numeric_constant::NC_UL_NOTINT:
- error_at(e->location(), "non-integer %s argument to make",
- is_length ? "len" : "cap");
- return false;
- case Numeric_constant::NC_UL_NEGATIVE:
- error_at(e->location(), "negative %s argument to make",
- is_length ? "len" : "cap");
- return false;
- case Numeric_constant::NC_UL_BIG:
- // We don't want to give a compile-time error for a 64-bit
- // value on a 32-bit target.
- return true;
- }
- }
-
- if (e->type()->integer_type() != NULL)
- return true;
-
- error_at(e->location(), "non-integer %s argument to make",
- is_length ? "len" : "cap");
- return false;
-}
-
-// Return the type of the real or imag functions, given the type of
-// the argument. We need to map complex to float, complex64 to
-// float32, and complex128 to float64, so it has to be done by name.
-// This returns NULL if it can't figure out the type.
-
-Type*
-Builtin_call_expression::real_imag_type(Type* arg_type)
-{
- if (arg_type == NULL || arg_type->is_abstract())
- return NULL;
- Named_type* nt = arg_type->named_type();
- if (nt == NULL)
- return NULL;
- while (nt->real_type()->named_type() != NULL)
- nt = nt->real_type()->named_type();
- if (nt->name() == "complex64")
- return Type::lookup_float_type("float32");
- else if (nt->name() == "complex128")
- return Type::lookup_float_type("float64");
- else
- return NULL;
-}
-
-// Return the type of the complex function, given the type of one of the
-// argments. Like real_imag_type, we have to map by name.
-
-Type*
-Builtin_call_expression::complex_type(Type* arg_type)
-{
- if (arg_type == NULL || arg_type->is_abstract())
- return NULL;
- Named_type* nt = arg_type->named_type();
- if (nt == NULL)
- return NULL;
- while (nt->real_type()->named_type() != NULL)
- nt = nt->real_type()->named_type();
- if (nt->name() == "float32")
- return Type::lookup_complex_type("complex64");
- else if (nt->name() == "float64")
- return Type::lookup_complex_type("complex128");
- else
- return NULL;
-}
-
-// Return a single argument, or NULL if there isn't one.
-
-Expression*
-Builtin_call_expression::one_arg() const
-{
- const Expression_list* args = this->args();
- if (args == NULL || args->size() != 1)
- return NULL;
- return args->front();
-}
-
-// A traversal class which looks for a call or receive expression.
-
-class Find_call_expression : public Traverse
-{
- public:
- Find_call_expression()
- : Traverse(traverse_expressions),
- found_(false)
- { }
-
- int
- expression(Expression**);
-
- bool
- found()
- { return this->found_; }
-
- private:
- bool found_;
-};
-
-int
-Find_call_expression::expression(Expression** pexpr)
-{
- if ((*pexpr)->call_expression() != NULL
- || (*pexpr)->receive_expression() != NULL)
- {
- this->found_ = true;
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Return whether this is constant: len of a string constant, or len
-// or cap of an array, or unsafe.Sizeof, unsafe.Offsetof,
-// unsafe.Alignof.
-
-bool
-Builtin_call_expression::do_is_constant() const
-{
- switch (this->code_)
- {
- case BUILTIN_LEN:
- case BUILTIN_CAP:
- {
- if (this->seen_)
- return false;
-
- Expression* arg = this->one_arg();
- if (arg == NULL)
- return false;
- Type* arg_type = arg->type();
-
- if (arg_type->points_to() != NULL
- && arg_type->points_to()->array_type() != NULL
- && !arg_type->points_to()->is_slice_type())
- arg_type = arg_type->points_to();
-
- // The len and cap functions are only constant if there are no
- // function calls or channel operations in the arguments.
- // Otherwise we have to make the call.
- if (!arg->is_constant())
- {
- Find_call_expression find_call;
- Expression::traverse(&arg, &find_call);
- if (find_call.found())
- return false;
- }
-
- if (arg_type->array_type() != NULL
- && arg_type->array_type()->length() != NULL)
- return true;
-
- if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
- {
- this->seen_ = true;
- bool ret = arg->is_constant();
- this->seen_ = false;
- return ret;
- }
- }
- break;
-
- case BUILTIN_SIZEOF:
- case BUILTIN_ALIGNOF:
- return this->one_arg() != NULL;
-
- case BUILTIN_OFFSETOF:
- {
- Expression* arg = this->one_arg();
- if (arg == NULL)
- return false;
- return arg->field_reference_expression() != NULL;
- }
-
- case BUILTIN_COMPLEX:
- {
- const Expression_list* args = this->args();
- if (args != NULL && args->size() == 2)
- return args->front()->is_constant() && args->back()->is_constant();
- }
- break;
-
- case BUILTIN_REAL:
- case BUILTIN_IMAG:
- {
- Expression* arg = this->one_arg();
- return arg != NULL && arg->is_constant();
- }
-
- default:
- break;
- }
-
- return false;
-}
-
-// Return a numeric constant if possible.
-
-bool
-Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
-{
- if (this->code_ == BUILTIN_LEN
- || this->code_ == BUILTIN_CAP)
- {
- Expression* arg = this->one_arg();
- if (arg == NULL)
- return false;
- Type* arg_type = arg->type();
-
- if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
- {
- std::string sval;
- if (arg->string_constant_value(&sval))
- {
- nc->set_unsigned_long(Type::lookup_integer_type("int"),
- sval.length());
- return true;
- }
- }
-
- if (arg_type->points_to() != NULL
- && arg_type->points_to()->array_type() != NULL
- && !arg_type->points_to()->is_slice_type())
- arg_type = arg_type->points_to();
-
- if (arg_type->array_type() != NULL
- && arg_type->array_type()->length() != NULL)
- {
- if (this->seen_)
- return false;
- Expression* e = arg_type->array_type()->length();
- this->seen_ = true;
- bool r = e->numeric_constant_value(nc);
- this->seen_ = false;
- if (r)
- {
- if (!nc->set_type(Type::lookup_integer_type("int"), false,
- this->location()))
- r = false;
- }
- return r;
- }
- }
- else if (this->code_ == BUILTIN_SIZEOF
- || this->code_ == BUILTIN_ALIGNOF)
- {
- Expression* arg = this->one_arg();
- if (arg == NULL)
- return false;
- Type* arg_type = arg->type();
- if (arg_type->is_error())
- return false;
- if (arg_type->is_abstract())
- return false;
- if (arg_type->named_type() != NULL)
- arg_type->named_type()->convert(this->gogo_);
-
- unsigned int ret;
- if (this->code_ == BUILTIN_SIZEOF)
- {
- if (!arg_type->backend_type_size(this->gogo_, &ret))
- return false;
- }
- else if (this->code_ == BUILTIN_ALIGNOF)
- {
- if (arg->field_reference_expression() == NULL)
- {
- if (!arg_type->backend_type_align(this->gogo_, &ret))
- return false;
- }
- else
- {
- // Calling unsafe.Alignof(s.f) returns the alignment of
- // the type of f when it is used as a field in a struct.
- if (!arg_type->backend_type_field_align(this->gogo_, &ret))
- return false;
- }
- }
- else
- go_unreachable();
-
- nc->set_unsigned_long(Type::lookup_integer_type("uintptr"),
- static_cast<unsigned long>(ret));
- return true;
- }
- else if (this->code_ == BUILTIN_OFFSETOF)
- {
- Expression* arg = this->one_arg();
- if (arg == NULL)
- return false;
- Field_reference_expression* farg = arg->field_reference_expression();
- if (farg == NULL)
- return false;
- Expression* struct_expr = farg->expr();
- Type* st = struct_expr->type();
- if (st->struct_type() == NULL)
- return false;
- if (st->named_type() != NULL)
- st->named_type()->convert(this->gogo_);
- unsigned int offset;
- if (!st->struct_type()->backend_field_offset(this->gogo_,
- farg->field_index(),
- &offset))
- return false;
- nc->set_unsigned_long(Type::lookup_integer_type("uintptr"),
- static_cast<unsigned long>(offset));
- return true;
- }
- else if (this->code_ == BUILTIN_REAL || this->code_ == BUILTIN_IMAG)
- {
- Expression* arg = this->one_arg();
- if (arg == NULL)
- return false;
-
- Numeric_constant argnc;
- if (!arg->numeric_constant_value(&argnc))
- return false;
-
- mpfr_t real;
- mpfr_t imag;
- if (!argnc.to_complex(&real, &imag))
- return false;
-
- Type* type = Builtin_call_expression::real_imag_type(argnc.type());
- if (this->code_ == BUILTIN_REAL)
- nc->set_float(type, real);
- else
- nc->set_float(type, imag);
- return true;
- }
- else if (this->code_ == BUILTIN_COMPLEX)
- {
- const Expression_list* args = this->args();
- if (args == NULL || args->size() != 2)
- return false;
-
- Numeric_constant rnc;
- if (!args->front()->numeric_constant_value(&rnc))
- return false;
- Numeric_constant inc;
- if (!args->back()->numeric_constant_value(&inc))
- return false;
-
- if (rnc.type() != NULL
- && !rnc.type()->is_abstract()
- && inc.type() != NULL
- && !inc.type()->is_abstract()
- && !Type::are_identical(rnc.type(), inc.type(), false, NULL))
- return false;
-
- mpfr_t r;
- if (!rnc.to_float(&r))
- return false;
- mpfr_t i;
- if (!inc.to_float(&i))
- {
- mpfr_clear(r);
- return false;
- }
-
- Type* arg_type = rnc.type();
- if (arg_type == NULL || arg_type->is_abstract())
- arg_type = inc.type();
-
- Type* type = Builtin_call_expression::complex_type(arg_type);
- nc->set_complex(type, r, i);
-
- mpfr_clear(r);
- mpfr_clear(i);
-
- return true;
- }
-
- return false;
-}
-
-// Give an error if we are discarding the value of an expression which
-// should not normally be discarded. We don't give an error for
-// discarding the value of an ordinary function call, but we do for
-// builtin functions, purely for consistency with the gc compiler.
-
-bool
-Builtin_call_expression::do_discarding_value()
-{
- switch (this->code_)
- {
- case BUILTIN_INVALID:
- default:
- go_unreachable();
-
- case BUILTIN_APPEND:
- case BUILTIN_CAP:
- case BUILTIN_COMPLEX:
- case BUILTIN_IMAG:
- case BUILTIN_LEN:
- case BUILTIN_MAKE:
- case BUILTIN_NEW:
- case BUILTIN_REAL:
- case BUILTIN_ALIGNOF:
- case BUILTIN_OFFSETOF:
- case BUILTIN_SIZEOF:
- this->unused_value_error();
- return false;
-
- case BUILTIN_CLOSE:
- case BUILTIN_COPY:
- case BUILTIN_DELETE:
- case BUILTIN_PANIC:
- case BUILTIN_PRINT:
- case BUILTIN_PRINTLN:
- case BUILTIN_RECOVER:
- return true;
- }
-}
-
-// Return the type.
-
-Type*
-Builtin_call_expression::do_type()
-{
- switch (this->code_)
- {
- case BUILTIN_INVALID:
- default:
- go_unreachable();
-
- case BUILTIN_NEW:
- case BUILTIN_MAKE:
- {
- const Expression_list* args = this->args();
- if (args == NULL || args->empty())
- return Type::make_error_type();
- return Type::make_pointer_type(args->front()->type());
- }
-
- case BUILTIN_CAP:
- case BUILTIN_COPY:
- case BUILTIN_LEN:
- return Type::lookup_integer_type("int");
-
- case BUILTIN_ALIGNOF:
- case BUILTIN_OFFSETOF:
- case BUILTIN_SIZEOF:
- return Type::lookup_integer_type("uintptr");
-
- case BUILTIN_CLOSE:
- case BUILTIN_DELETE:
- case BUILTIN_PANIC:
- case BUILTIN_PRINT:
- case BUILTIN_PRINTLN:
- return Type::make_void_type();
-
- case BUILTIN_RECOVER:
- return Type::make_empty_interface_type(Linemap::predeclared_location());
-
- case BUILTIN_APPEND:
- {
- const Expression_list* args = this->args();
- if (args == NULL || args->empty())
- return Type::make_error_type();
- return args->front()->type();
- }
-
- case BUILTIN_REAL:
- case BUILTIN_IMAG:
- {
- Expression* arg = this->one_arg();
- if (arg == NULL)
- return Type::make_error_type();
- Type* t = arg->type();
- if (t->is_abstract())
- t = t->make_non_abstract_type();
- t = Builtin_call_expression::real_imag_type(t);
- if (t == NULL)
- t = Type::make_error_type();
- return t;
- }
-
- case BUILTIN_COMPLEX:
- {
- const Expression_list* args = this->args();
- if (args == NULL || args->size() != 2)
- return Type::make_error_type();
- Type* t = args->front()->type();
- if (t->is_abstract())
- {
- t = args->back()->type();
- if (t->is_abstract())
- t = t->make_non_abstract_type();
- }
- t = Builtin_call_expression::complex_type(t);
- if (t == NULL)
- t = Type::make_error_type();
- return t;
- }
- }
-}
-
-// Determine the type.
-
-void
-Builtin_call_expression::do_determine_type(const Type_context* context)
-{
- if (!this->determining_types())
- return;
-
- this->fn()->determine_type_no_context();
-
- const Expression_list* args = this->args();
-
- bool is_print;
- Type* arg_type = NULL;
- switch (this->code_)
- {
- case BUILTIN_PRINT:
- case BUILTIN_PRINTLN:
- // Do not force a large integer constant to "int".
- is_print = true;
- break;
-
- case BUILTIN_REAL:
- case BUILTIN_IMAG:
- arg_type = Builtin_call_expression::complex_type(context->type);
- is_print = false;
- break;
-
- case BUILTIN_COMPLEX:
- {
- // For the complex function the type of one operand can
- // determine the type of the other, as in a binary expression.
- arg_type = Builtin_call_expression::real_imag_type(context->type);
- if (args != NULL && args->size() == 2)
- {
- Type* t1 = args->front()->type();
- Type* t2 = args->back()->type();
- if (!t1->is_abstract())
- arg_type = t1;
- else if (!t2->is_abstract())
- arg_type = t2;
- }
- is_print = false;
- }
- break;
-
- default:
- is_print = false;
- break;
- }
-
- if (args != NULL)
- {
- for (Expression_list::const_iterator pa = args->begin();
- pa != args->end();
- ++pa)
- {
- Type_context subcontext;
- subcontext.type = arg_type;
-
- if (is_print)
- {
- // We want to print large constants, we so can't just
- // use the appropriate nonabstract type. Use uint64 for
- // an integer if we know it is nonnegative, otherwise
- // use int64 for a integer, otherwise use float64 for a
- // float or complex128 for a complex.
- Type* want_type = NULL;
- Type* atype = (*pa)->type();
- if (atype->is_abstract())
- {
- if (atype->integer_type() != NULL)
- {
- Numeric_constant nc;
- if (this->numeric_constant_value(&nc))
- {
- mpz_t val;
- if (nc.to_int(&val))
- {
- if (mpz_sgn(val) >= 0)
- want_type = Type::lookup_integer_type("uint64");
- mpz_clear(val);
- }
- }
- if (want_type == NULL)
- want_type = Type::lookup_integer_type("int64");
- }
- else if (atype->float_type() != NULL)
- want_type = Type::lookup_float_type("float64");
- else if (atype->complex_type() != NULL)
- want_type = Type::lookup_complex_type("complex128");
- else if (atype->is_abstract_string_type())
- want_type = Type::lookup_string_type();
- else if (atype->is_abstract_boolean_type())
- want_type = Type::lookup_bool_type();
- else
- go_unreachable();
- subcontext.type = want_type;
- }
- }
-
- (*pa)->determine_type(&subcontext);
- }
- }
-}
-
-// If there is exactly one argument, return true. Otherwise give an
-// error message and return false.
-
-bool
-Builtin_call_expression::check_one_arg()
-{
- const Expression_list* args = this->args();
- if (args == NULL || args->size() < 1)
- {
- this->report_error(_("not enough arguments"));
- return false;
- }
- else if (args->size() > 1)
- {
- this->report_error(_("too many arguments"));
- return false;
- }
- if (args->front()->is_error_expression()
- || args->front()->type()->is_error())
- {
- this->set_is_error();
- return false;
- }
- return true;
-}
-
-// Check argument types for a builtin function.
-
-void
-Builtin_call_expression::do_check_types(Gogo*)
-{
- if (this->is_error_expression())
- return;
- switch (this->code_)
- {
- case BUILTIN_INVALID:
- case BUILTIN_NEW:
- case BUILTIN_MAKE:
- case BUILTIN_DELETE:
- return;
-
- case BUILTIN_LEN:
- case BUILTIN_CAP:
- {
- // The single argument may be either a string or an array or a
- // map or a channel, or a pointer to a closed array.
- if (this->check_one_arg())
- {
- Type* arg_type = this->one_arg()->type();
- if (arg_type->points_to() != NULL
- && arg_type->points_to()->array_type() != NULL
- && !arg_type->points_to()->is_slice_type())
- arg_type = arg_type->points_to();
- if (this->code_ == BUILTIN_CAP)
- {
- if (!arg_type->is_error()
- && arg_type->array_type() == NULL
- && arg_type->channel_type() == NULL)
- this->report_error(_("argument must be array or slice "
- "or channel"));
- }
- else
- {
- if (!arg_type->is_error()
- && !arg_type->is_string_type()
- && arg_type->array_type() == NULL
- && arg_type->map_type() == NULL
- && arg_type->channel_type() == NULL)
- this->report_error(_("argument must be string or "
- "array or slice or map or channel"));
- }
- }
- }
- break;
-
- case BUILTIN_PRINT:
- case BUILTIN_PRINTLN:
- {
- const Expression_list* args = this->args();
- if (args == NULL)
- {
- if (this->code_ == BUILTIN_PRINT)
- warning_at(this->location(), 0,
- "no arguments for builtin function %<%s%>",
- (this->code_ == BUILTIN_PRINT
- ? "print"
- : "println"));
- }
- else
- {
- for (Expression_list::const_iterator p = args->begin();
- p != args->end();
- ++p)
- {
- Type* type = (*p)->type();
- if (type->is_error()
- || type->is_string_type()
- || type->integer_type() != NULL
- || type->float_type() != NULL
- || type->complex_type() != NULL
- || type->is_boolean_type()
- || type->points_to() != NULL
- || type->interface_type() != NULL
- || type->channel_type() != NULL
- || type->map_type() != NULL
- || type->function_type() != NULL
- || type->is_slice_type())
- ;
- else if ((*p)->is_type_expression())
- {
- // If this is a type expression it's going to give
- // an error anyhow, so we don't need one here.
- }
- else
- this->report_error(_("unsupported argument type to "
- "builtin function"));
- }
- }
- }
- break;
-
- case BUILTIN_CLOSE:
- if (this->check_one_arg())
- {
- if (this->one_arg()->type()->channel_type() == NULL)
- this->report_error(_("argument must be channel"));
- else if (!this->one_arg()->type()->channel_type()->may_send())
- this->report_error(_("cannot close receive-only channel"));
- }
- break;
-
- case BUILTIN_PANIC:
- case BUILTIN_SIZEOF:
- case BUILTIN_ALIGNOF:
- this->check_one_arg();
- break;
-
- case BUILTIN_RECOVER:
- if (this->args() != NULL && !this->args()->empty())
- this->report_error(_("too many arguments"));
- break;
-
- case BUILTIN_OFFSETOF:
- if (this->check_one_arg())
- {
- Expression* arg = this->one_arg();
- if (arg->field_reference_expression() == NULL)
- this->report_error(_("argument must be a field reference"));
- }
- break;
-
- case BUILTIN_COPY:
- {
- const Expression_list* args = this->args();
- if (args == NULL || args->size() < 2)
- {
- this->report_error(_("not enough arguments"));
- break;
- }
- else if (args->size() > 2)
- {
- this->report_error(_("too many arguments"));
- break;
- }
- Type* arg1_type = args->front()->type();
- Type* arg2_type = args->back()->type();
- if (arg1_type->is_error() || arg2_type->is_error())
- break;
-
- Type* e1;
- if (arg1_type->is_slice_type())
- e1 = arg1_type->array_type()->element_type();
- else
- {
- this->report_error(_("left argument must be a slice"));
- break;
- }
-
- if (arg2_type->is_slice_type())
- {
- Type* e2 = arg2_type->array_type()->element_type();
- if (!Type::are_identical(e1, e2, true, NULL))
- this->report_error(_("element types must be the same"));
- }
- else if (arg2_type->is_string_type())
- {
- if (e1->integer_type() == NULL || !e1->integer_type()->is_byte())
- this->report_error(_("first argument must be []byte"));
- }
- else
- this->report_error(_("second argument must be slice or string"));
- }
- break;
-
- case BUILTIN_APPEND:
- {
- const Expression_list* args = this->args();
- if (args == NULL || args->size() < 2)
- {
- this->report_error(_("not enough arguments"));
- break;
- }
- if (args->size() > 2)
- {
- this->report_error(_("too many arguments"));
- break;
- }
- if (args->front()->type()->is_error()
- || args->back()->type()->is_error())
- break;
-
- Array_type* at = args->front()->type()->array_type();
- Type* e = at->element_type();
-
- // The language permits appending a string to a []byte, as a
- // special case.
- if (args->back()->type()->is_string_type())
- {
- if (e->integer_type() != NULL && e->integer_type()->is_byte())
- break;
- }
-
- // The language says that the second argument must be
- // assignable to a slice of the element type of the first
- // argument. We already know the first argument is a slice
- // type.
- Type* arg2_type = Type::make_array_type(e, NULL);
- std::string reason;
- if (!Type::are_assignable(arg2_type, args->back()->type(), &reason))
- {
- if (reason.empty())
- this->report_error(_("argument 2 has invalid type"));
- else
- {
- error_at(this->location(), "argument 2 has invalid type (%s)",
- reason.c_str());
- this->set_is_error();
- }
- }
- break;
- }
-
- case BUILTIN_REAL:
- case BUILTIN_IMAG:
- if (this->check_one_arg())
- {
- if (this->one_arg()->type()->complex_type() == NULL)
- this->report_error(_("argument must have complex type"));
- }
- break;
-
- case BUILTIN_COMPLEX:
- {
- const Expression_list* args = this->args();
- if (args == NULL || args->size() < 2)
- this->report_error(_("not enough arguments"));
- else if (args->size() > 2)
- this->report_error(_("too many arguments"));
- else if (args->front()->is_error_expression()
- || args->front()->type()->is_error()
- || args->back()->is_error_expression()
- || args->back()->type()->is_error())
- this->set_is_error();
- else if (!Type::are_identical(args->front()->type(),
- args->back()->type(), true, NULL))
- this->report_error(_("complex arguments must have identical types"));
- else if (args->front()->type()->float_type() == NULL)
- this->report_error(_("complex arguments must have "
- "floating-point type"));
- }
- break;
-
- default:
- go_unreachable();
- }
-}
-
-// Return the tree for a builtin function.
-
-tree
-Builtin_call_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
- Location location = this->location();
- switch (this->code_)
- {
- case BUILTIN_INVALID:
- case BUILTIN_NEW:
- case BUILTIN_MAKE:
- go_unreachable();
-
- case BUILTIN_LEN:
- case BUILTIN_CAP:
- {
- const Expression_list* args = this->args();
- go_assert(args != NULL && args->size() == 1);
- Expression* arg = *args->begin();
- Type* arg_type = arg->type();
-
- if (this->seen_)
- {
- go_assert(saw_errors());
- return error_mark_node;
- }
- this->seen_ = true;
-
- tree arg_tree = arg->get_tree(context);
-
- this->seen_ = false;
-
- if (arg_tree == error_mark_node)
- return error_mark_node;
-
- if (arg_type->points_to() != NULL)
- {
- arg_type = arg_type->points_to();
- go_assert(arg_type->array_type() != NULL
- && !arg_type->is_slice_type());
- go_assert(POINTER_TYPE_P(TREE_TYPE(arg_tree)));
- arg_tree = build_fold_indirect_ref(arg_tree);
- }
-
- Type* int_type = Type::lookup_integer_type("int");
- tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
-
- tree val_tree;
- if (this->code_ == BUILTIN_LEN)
- {
- if (arg_type->is_string_type())
- val_tree = String_type::length_tree(gogo, arg_tree);
- else if (arg_type->array_type() != NULL)
- {
- if (this->seen_)
- {
- go_assert(saw_errors());
- return error_mark_node;
- }
- this->seen_ = true;
- val_tree = arg_type->array_type()->length_tree(gogo, arg_tree);
- this->seen_ = false;
- }
- else if (arg_type->map_type() != NULL)
- {
- tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo));
- static tree map_len_fndecl;
- val_tree = Gogo::call_builtin(&map_len_fndecl,
- location,
- "__go_map_len",
- 1,
- int_type_tree,
- arg_type_tree,
- arg_tree);
- }
- else if (arg_type->channel_type() != NULL)
- {
- tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo));
- static tree chan_len_fndecl;
- val_tree = Gogo::call_builtin(&chan_len_fndecl,
- location,
- "__go_chan_len",
- 1,
- int_type_tree,
- arg_type_tree,
- arg_tree);
- }
- else
- go_unreachable();
- }
- else
- {
- if (arg_type->array_type() != NULL)
- {
- if (this->seen_)
- {
- go_assert(saw_errors());
- return error_mark_node;
- }
- this->seen_ = true;
- val_tree = arg_type->array_type()->capacity_tree(gogo,
- arg_tree);
- this->seen_ = false;
- }
- else if (arg_type->channel_type() != NULL)
- {
- tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo));
- static tree chan_cap_fndecl;
- val_tree = Gogo::call_builtin(&chan_cap_fndecl,
- location,
- "__go_chan_cap",
- 1,
- int_type_tree,
- arg_type_tree,
- arg_tree);
- }
- else
- go_unreachable();
- }
-
- return fold_convert_loc(location.gcc_location(), int_type_tree,
- val_tree);
- }
-
- case BUILTIN_PRINT:
- case BUILTIN_PRINTLN:
- {
- const bool is_ln = this->code_ == BUILTIN_PRINTLN;
- tree stmt_list = NULL_TREE;
-
- const Expression_list* call_args = this->args();
- if (call_args != NULL)
- {
- for (Expression_list::const_iterator p = call_args->begin();
- p != call_args->end();
- ++p)
- {
- if (is_ln && p != call_args->begin())
- {
- static tree print_space_fndecl;
- tree call = Gogo::call_builtin(&print_space_fndecl,
- location,
- "__go_print_space",
- 0,
- void_type_node);
- if (call == error_mark_node)
- return error_mark_node;
- append_to_statement_list(call, &stmt_list);
- }
-
- Type* type = (*p)->type();
-
- tree arg = (*p)->get_tree(context);
- if (arg == error_mark_node)
- return error_mark_node;
-
- tree* pfndecl;
- const char* fnname;
- if (type->is_string_type())
- {
- static tree print_string_fndecl;
- pfndecl = &print_string_fndecl;
- fnname = "__go_print_string";
- }
- else if (type->integer_type() != NULL
- && type->integer_type()->is_unsigned())
- {
- static tree print_uint64_fndecl;
- pfndecl = &print_uint64_fndecl;
- fnname = "__go_print_uint64";
- Type* itype = Type::lookup_integer_type("uint64");
- Btype* bitype = itype->get_backend(gogo);
- arg = fold_convert_loc(location.gcc_location(),
- type_to_tree(bitype), arg);
- }
- else if (type->integer_type() != NULL)
- {
- static tree print_int64_fndecl;
- pfndecl = &print_int64_fndecl;
- fnname = "__go_print_int64";
- Type* itype = Type::lookup_integer_type("int64");
- Btype* bitype = itype->get_backend(gogo);
- arg = fold_convert_loc(location.gcc_location(),
- type_to_tree(bitype), arg);
- }
- else if (type->float_type() != NULL)
- {
- static tree print_double_fndecl;
- pfndecl = &print_double_fndecl;
- fnname = "__go_print_double";
- arg = fold_convert_loc(location.gcc_location(),
- double_type_node, arg);
- }
- else if (type->complex_type() != NULL)
- {
- static tree print_complex_fndecl;
- pfndecl = &print_complex_fndecl;
- fnname = "__go_print_complex";
- arg = fold_convert_loc(location.gcc_location(),
- complex_double_type_node, arg);
- }
- else if (type->is_boolean_type())
- {
- static tree print_bool_fndecl;
- pfndecl = &print_bool_fndecl;
- fnname = "__go_print_bool";
- }
- else if (type->points_to() != NULL
- || type->channel_type() != NULL
- || type->map_type() != NULL
- || type->function_type() != NULL)
- {
- static tree print_pointer_fndecl;
- pfndecl = &print_pointer_fndecl;
- fnname = "__go_print_pointer";
- arg = fold_convert_loc(location.gcc_location(),
- ptr_type_node, arg);
- }
- else if (type->interface_type() != NULL)
- {
- if (type->interface_type()->is_empty())
- {
- static tree print_empty_interface_fndecl;
- pfndecl = &print_empty_interface_fndecl;
- fnname = "__go_print_empty_interface";
- }
- else
- {
- static tree print_interface_fndecl;
- pfndecl = &print_interface_fndecl;
- fnname = "__go_print_interface";
- }
- }
- else if (type->is_slice_type())
- {
- static tree print_slice_fndecl;
- pfndecl = &print_slice_fndecl;
- fnname = "__go_print_slice";
- }
- else
- {
- go_assert(saw_errors());
- return error_mark_node;
- }
-
- tree call = Gogo::call_builtin(pfndecl,
- location,
- fnname,
- 1,
- void_type_node,
- TREE_TYPE(arg),
- arg);
- if (call == error_mark_node)
- return error_mark_node;
- append_to_statement_list(call, &stmt_list);
- }
- }
-
- if (is_ln)
- {
- static tree print_nl_fndecl;
- tree call = Gogo::call_builtin(&print_nl_fndecl,
- location,
- "__go_print_nl",
- 0,
- void_type_node);
- if (call == error_mark_node)
- return error_mark_node;
- append_to_statement_list(call, &stmt_list);
- }
-
- return stmt_list;
- }
-
- case BUILTIN_PANIC:
- {
- const Expression_list* args = this->args();
- go_assert(args != NULL && args->size() == 1);
- Expression* arg = args->front();
- tree arg_tree = arg->get_tree(context);
- if (arg_tree == error_mark_node)
- return error_mark_node;
- Type *empty =
- Type::make_empty_interface_type(Linemap::predeclared_location());
- arg_tree = Expression::convert_for_assignment(context, empty,
- arg->type(),
- arg_tree, location);
- static tree panic_fndecl;
- tree call = Gogo::call_builtin(&panic_fndecl,
- location,
- "__go_panic",
- 1,
- 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.
- TREE_THIS_VOLATILE(panic_fndecl) = 1;
- return call;
- }
-
- case BUILTIN_RECOVER:
- {
- // The argument is set when building recover thunks. It's a
- // boolean value which is true if we can recover a value now.
- const Expression_list* args = this->args();
- go_assert(args != NULL && args->size() == 1);
- Expression* arg = args->front();
- tree arg_tree = arg->get_tree(context);
- if (arg_tree == error_mark_node)
- return error_mark_node;
-
- Type *empty =
- Type::make_empty_interface_type(Linemap::predeclared_location());
- tree empty_tree = type_to_tree(empty->get_backend(context->gogo()));
-
- Type* nil_type = Type::make_nil_type();
- Expression* nil = Expression::make_nil(location);
- tree nil_tree = nil->get_tree(context);
- tree empty_nil_tree = Expression::convert_for_assignment(context,
- empty,
- nil_type,
- nil_tree,
- location);
-
- // We need to handle a deferred call to recover specially,
- // because it changes whether it can recover a panic or not.
- // See test7 in test/recover1.go.
- tree call;
- if (this->is_deferred())
- {
- static tree deferred_recover_fndecl;
- call = Gogo::call_builtin(&deferred_recover_fndecl,
- location,
- "__go_deferred_recover",
- 0,
- empty_tree);
- }
- else
- {
- static tree recover_fndecl;
- call = Gogo::call_builtin(&recover_fndecl,
- location,
- "__go_recover",
- 0,
- empty_tree);
- }
- if (call == error_mark_node)
- return error_mark_node;
- return fold_build3_loc(location.gcc_location(), COND_EXPR, empty_tree,
- arg_tree, call, empty_nil_tree);
- }
-
- case BUILTIN_CLOSE:
- {
- const Expression_list* args = this->args();
- go_assert(args != NULL && args->size() == 1);
- Expression* arg = args->front();
- tree arg_tree = arg->get_tree(context);
- if (arg_tree == error_mark_node)
- return error_mark_node;
- static tree close_fndecl;
- return Gogo::call_builtin(&close_fndecl,
- location,
- "__go_builtin_close",
- 1,
- void_type_node,
- TREE_TYPE(arg_tree),
- arg_tree);
- }
-
- case BUILTIN_SIZEOF:
- case BUILTIN_OFFSETOF:
- case BUILTIN_ALIGNOF:
- {
- Numeric_constant nc;
- unsigned long val;
- if (!this->numeric_constant_value(&nc)
- || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
- {
- go_assert(saw_errors());
- return error_mark_node;
- }
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
- tree type = type_to_tree(uintptr_type->get_backend(gogo));
- return build_int_cst(type, val);
- }
-
- case BUILTIN_COPY:
- {
- const Expression_list* args = this->args();
- go_assert(args != NULL && args->size() == 2);
- Expression* arg1 = args->front();
- Expression* arg2 = args->back();
-
- 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;
-
- Type* arg1_type = arg1->type();
- Array_type* at = arg1_type->array_type();
- 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;
- tree arg2_len;
- if (arg2_type->is_slice_type())
- {
- at = arg2_type->array_type();
- arg2_tree = save_expr(arg2_tree);
- arg2_val = at->value_pointer_tree(gogo, arg2_tree);
- arg2_len = at->length_tree(gogo, arg2_tree);
- }
- else
- {
- arg2_tree = save_expr(arg2_tree);
- 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);
- tree len = fold_build3_loc(location.gcc_location(), COND_EXPR,
- TREE_TYPE(arg1_len),
- fold_build2_loc(location.gcc_location(),
- LT_EXPR, boolean_type_node,
- arg1_len, arg2_len),
- arg1_len, arg2_len);
- len = save_expr(len);
-
- Type* element_type = at->element_type();
- Btype* element_btype = element_type->get_backend(gogo);
- tree element_type_tree = type_to_tree(element_btype);
- 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.gcc_location(),
- TREE_TYPE(element_size), len);
- bytecount = fold_build2_loc(location.gcc_location(), MULT_EXPR,
- TREE_TYPE(element_size),
- bytecount, element_size);
- bytecount = fold_convert_loc(location.gcc_location(), size_type_node,
- bytecount);
-
- arg1_val = fold_convert_loc(location.gcc_location(), ptr_type_node,
- arg1_val);
- arg2_val = fold_convert_loc(location.gcc_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.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(len), call, len);
- }
-
- case BUILTIN_APPEND:
- {
- const Expression_list* args = this->args();
- go_assert(args != NULL && args->size() == 2);
- Expression* arg1 = args->front();
- Expression* arg2 = args->back();
-
- 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;
-
- Array_type* at = arg1->type()->array_type();
- Type* element_type = at->element_type()->forwarded();
-
- tree arg2_val;
- tree arg2_len;
- tree element_size;
- if (arg2->type()->is_string_type()
- && element_type->integer_type() != NULL
- && element_type->integer_type()->is_byte())
- {
- arg2_tree = save_expr(arg2_tree);
- arg2_val = String_type::bytes_tree(gogo, arg2_tree);
- arg2_len = String_type::length_tree(gogo, arg2_tree);
- element_size = size_int(1);
- }
- else
- {
- arg2_tree = Expression::convert_for_assignment(context, at,
- arg2->type(),
- arg2_tree,
- location);
- if (arg2_tree == error_mark_node)
- return error_mark_node;
-
- arg2_tree = save_expr(arg2_tree);
-
- arg2_val = at->value_pointer_tree(gogo, arg2_tree);
- arg2_len = at->length_tree(gogo, arg2_tree);
-
- Btype* element_btype = element_type->get_backend(gogo);
- tree element_type_tree = type_to_tree(element_btype);
- if (element_type_tree == error_mark_node)
- return error_mark_node;
- element_size = TYPE_SIZE_UNIT(element_type_tree);
- }
-
- arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node,
- arg2_val);
- arg2_len = fold_convert_loc(location.gcc_location(), size_type_node,
- arg2_len);
- element_size = fold_convert_loc(location.gcc_location(), size_type_node,
- element_size);
-
- if (arg2_val == error_mark_node
- || arg2_len == error_mark_node
- || element_size == error_mark_node)
- return error_mark_node;
-
- // We rebuild the decl each time since the slice types may
- // change.
- tree append_fndecl = NULL_TREE;
- return Gogo::call_builtin(&append_fndecl,
- location,
- "__go_append",
- 4,
- TREE_TYPE(arg1_tree),
- TREE_TYPE(arg1_tree),
- arg1_tree,
- ptr_type_node,
- arg2_val,
- size_type_node,
- arg2_len,
- size_type_node,
- element_size);
- }
-
- case BUILTIN_REAL:
- case BUILTIN_IMAG:
- {
- const Expression_list* args = this->args();
- go_assert(args != NULL && args->size() == 1);
- Expression* arg = args->front();
- tree arg_tree = arg->get_tree(context);
- if (arg_tree == error_mark_node)
- return error_mark_node;
- go_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(arg_tree)));
- if (this->code_ == BUILTIN_REAL)
- return fold_build1_loc(location.gcc_location(), REALPART_EXPR,
- TREE_TYPE(TREE_TYPE(arg_tree)),
- arg_tree);
- else
- return fold_build1_loc(location.gcc_location(), IMAGPART_EXPR,
- TREE_TYPE(TREE_TYPE(arg_tree)),
- arg_tree);
- }
-
- case BUILTIN_COMPLEX:
- {
- const Expression_list* args = this->args();
- go_assert(args != NULL && args->size() == 2);
- tree r = args->front()->get_tree(context);
- tree i = args->back()->get_tree(context);
- if (r == error_mark_node || i == error_mark_node)
- return error_mark_node;
- go_assert(TYPE_MAIN_VARIANT(TREE_TYPE(r))
- == TYPE_MAIN_VARIANT(TREE_TYPE(i)));
- go_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(r)));
- return fold_build2_loc(location.gcc_location(), COMPLEX_EXPR,
- build_complex_type(TREE_TYPE(r)),
- r, i);
- }
-
- default:
- go_unreachable();
- }
-}
-
-// We have to support exporting a builtin call expression, because
-// code can set a constant to the result of a builtin expression.
-
-void
-Builtin_call_expression::do_export(Export* exp) const
-{
- Numeric_constant nc;
- if (!this->numeric_constant_value(&nc))
- {
- error_at(this->location(), "value is not constant");
- return;
- }
-
- if (nc.is_int())
- {
- mpz_t val;
- nc.get_int(&val);
- Integer_expression::export_integer(exp, val);
- mpz_clear(val);
- }
- else if (nc.is_float())
- {
- mpfr_t fval;
- nc.get_float(&fval);
- Float_expression::export_float(exp, fval);
- mpfr_clear(fval);
- }
- else if (nc.is_complex())
- {
- mpfr_t real;
- mpfr_t imag;
- Complex_expression::export_complex(exp, real, imag);
- mpfr_clear(real);
- mpfr_clear(imag);
- }
- else
- go_unreachable();
-
- // A trailing space lets us reliably identify the end of the number.
- exp->write_c_string(" ");
-}
-
-// Class Call_expression.
-
-// Traversal.
-
-int
-Call_expression::do_traverse(Traverse* traverse)
-{
- if (Expression::traverse(&this->fn_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (this->args_ != NULL)
- {
- if (this->args_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Lower a call statement.
-
-Expression*
-Call_expression::do_lower(Gogo* gogo, Named_object* function,
- Statement_inserter* inserter, int)
-{
- Location loc = this->location();
-
- // A type cast can look like a function call.
- if (this->fn_->is_type_expression()
- && this->args_ != NULL
- && this->args_->size() == 1)
- return Expression::make_cast(this->fn_->type(), this->args_->front(),
- loc);
-
- // Because do_type will return an error type and thus prevent future
- // errors, check for that case now to ensure that the error gets
- // reported.
- if (this->get_function_type() == NULL)
- {
- if (!this->fn_->type()->is_error())
- this->report_error(_("expected function"));
- return Expression::make_error(loc);
- }
-
- // Recognize a call to a builtin function.
- Func_expression* fne = this->fn_->func_expression();
- if (fne != NULL
- && fne->named_object()->is_function_declaration()
- && fne->named_object()->func_declaration_value()->type()->is_builtin())
- return new Builtin_call_expression(gogo, this->fn_, this->args_,
- this->is_varargs_, loc);
-
- // Handle an argument which is a call to a function which returns
- // multiple results.
- if (this->args_ != NULL
- && this->args_->size() == 1
- && this->args_->front()->call_expression() != NULL
- && this->fn_->type()->function_type() != NULL)
- {
- Function_type* fntype = this->fn_->type()->function_type();
- size_t rc = this->args_->front()->call_expression()->result_count();
- if (rc > 1
- && fntype->parameters() != NULL
- && (fntype->parameters()->size() == rc
- || (fntype->is_varargs()
- && fntype->parameters()->size() - 1 <= rc)))
- {
- Call_expression* call = this->args_->front()->call_expression();
- Expression_list* args = new Expression_list;
- for (size_t i = 0; i < rc; ++i)
- args->push_back(Expression::make_call_result(call, i));
- // We can't return a new call expression here, because this
- // one may be referenced by Call_result expressions. We
- // also can't delete the old arguments, because we may still
- // traverse them somewhere up the call stack. FIXME.
- this->args_ = args;
- }
- }
-
- // If this call returns multiple results, create a temporary
- // variable for each result.
- size_t rc = this->result_count();
- if (rc > 1 && this->results_ == NULL)
- {
- std::vector<Temporary_statement*>* temps =
- new std::vector<Temporary_statement*>;
- temps->reserve(rc);
- const Typed_identifier_list* results =
- this->fn_->type()->function_type()->results();
- for (Typed_identifier_list::const_iterator p = results->begin();
- p != results->end();
- ++p)
- {
- Temporary_statement* temp = Statement::make_temporary(p->type(),
- NULL, loc);
- inserter->insert(temp);
- temps->push_back(temp);
- }
- this->results_ = temps;
- }
-
- // Handle a call to a varargs function by packaging up the extra
- // parameters.
- if (this->fn_->type()->function_type() != NULL
- && this->fn_->type()->function_type()->is_varargs())
- {
- Function_type* fntype = this->fn_->type()->function_type();
- const Typed_identifier_list* parameters = fntype->parameters();
- go_assert(parameters != NULL && !parameters->empty());
- Type* varargs_type = parameters->back().type();
- this->lower_varargs(gogo, function, inserter, varargs_type,
- parameters->size());
- }
-
- // If this is call to a method, call the method directly passing the
- // object as the first parameter.
- Bound_method_expression* bme = this->fn_->bound_method_expression();
- if (bme != NULL)
- {
- Named_object* method = bme->method();
- Expression* first_arg = bme->first_argument();
-
- // We always pass a pointer when calling a method.
- if (first_arg->type()->points_to() == NULL
- && !first_arg->type()->is_error())
- {
- first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc);
- // We may need to create a temporary variable so that we can
- // take the address. We can't do that here because it will
- // mess up the order of evaluation.
- Unary_expression* ue = static_cast<Unary_expression*>(first_arg);
- ue->set_create_temp();
- }
-
- // If we are calling a method which was inherited from an
- // embedded struct, and the method did not get a stub, then the
- // first type may be wrong.
- Type* fatype = bme->first_argument_type();
- if (fatype != NULL)
- {
- if (fatype->points_to() == NULL)
- fatype = Type::make_pointer_type(fatype);
- first_arg = Expression::make_unsafe_cast(fatype, first_arg, loc);
- }
-
- Expression_list* new_args = new Expression_list();
- new_args->push_back(first_arg);
- if (this->args_ != NULL)
- {
- for (Expression_list::const_iterator p = this->args_->begin();
- p != this->args_->end();
- ++p)
- new_args->push_back(*p);
- }
-
- // We have to change in place because this structure may be
- // referenced by Call_result_expressions. We can't delete the
- // old arguments, because we may be traversing them up in some
- // caller. FIXME.
- this->args_ = new_args;
- this->fn_ = Expression::make_func_reference(method, NULL,
- bme->location());
- }
-
- return this;
-}
-
-// Lower a call to a varargs function. FUNCTION is the function in
-// which the call occurs--it's not the function we are calling.
-// VARARGS_TYPE is the type of the varargs parameter, a slice type.
-// PARAM_COUNT is the number of parameters of the function we are
-// calling; the last of these parameters will be the varargs
-// parameter.
-
-void
-Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
- Statement_inserter* inserter,
- Type* varargs_type, size_t param_count)
-{
- if (this->varargs_are_lowered_)
- return;
-
- Location loc = this->location();
-
- go_assert(param_count > 0);
- go_assert(varargs_type->is_slice_type());
-
- size_t arg_count = this->args_ == NULL ? 0 : this->args_->size();
- if (arg_count < param_count - 1)
- {
- // Not enough arguments; will be caught in check_types.
- return;
- }
-
- Expression_list* old_args = this->args_;
- Expression_list* new_args = new Expression_list();
- bool push_empty_arg = false;
- if (old_args == NULL || old_args->empty())
- {
- go_assert(param_count == 1);
- push_empty_arg = true;
- }
- else
- {
- Expression_list::const_iterator pa;
- int i = 1;
- for (pa = old_args->begin(); pa != old_args->end(); ++pa, ++i)
- {
- if (static_cast<size_t>(i) == param_count)
- break;
- new_args->push_back(*pa);
- }
-
- // We have reached the varargs parameter.
-
- bool issued_error = false;
- if (pa == old_args->end())
- push_empty_arg = true;
- else if (pa + 1 == old_args->end() && this->is_varargs_)
- new_args->push_back(*pa);
- else if (this->is_varargs_)
- {
- if ((*pa)->type()->is_slice_type())
- this->report_error(_("too many arguments"));
- else
- {
- error_at(this->location(),
- _("invalid use of %<...%> with non-slice"));
- this->set_is_error();
- }
- return;
- }
- else
- {
- Type* element_type = varargs_type->array_type()->element_type();
- Expression_list* vals = new Expression_list;
- for (; pa != old_args->end(); ++pa, ++i)
- {
- // Check types here so that we get a better message.
- Type* patype = (*pa)->type();
- Location paloc = (*pa)->location();
- if (!this->check_argument_type(i, element_type, patype,
- paloc, issued_error))
- continue;
- vals->push_back(*pa);
- }
- Expression* val =
- Expression::make_slice_composite_literal(varargs_type, vals, loc);
- gogo->lower_expression(function, inserter, &val);
- new_args->push_back(val);
- }
- }
-
- if (push_empty_arg)
- new_args->push_back(Expression::make_nil(loc));
-
- // We can't return a new call expression here, because this one may
- // be referenced by Call_result expressions. FIXME. We can't
- // delete OLD_ARGS because we may have both a Call_expression and a
- // Builtin_call_expression which refer to them. FIXME.
- this->args_ = new_args;
- this->varargs_are_lowered_ = true;
-}
-
-// Get the function type. This can return NULL in error cases.
-
-Function_type*
-Call_expression::get_function_type() const
-{
- return this->fn_->type()->function_type();
-}
-
-// Return the number of values which this call will return.
-
-size_t
-Call_expression::result_count() const
-{
- const Function_type* fntype = this->get_function_type();
- if (fntype == NULL)
- return 0;
- if (fntype->results() == NULL)
- return 0;
- return fntype->results()->size();
-}
-
-// Return the temporary which holds a result.
-
-Temporary_statement*
-Call_expression::result(size_t i) const
-{
- if (this->results_ == NULL || this->results_->size() <= i)
- {
- go_assert(saw_errors());
- return NULL;
- }
- return (*this->results_)[i];
-}
-
-// Return whether this is a call to the predeclared function recover.
-
-bool
-Call_expression::is_recover_call() const
-{
- return this->do_is_recover_call();
-}
-
-// Set the argument to the recover function.
-
-void
-Call_expression::set_recover_arg(Expression* arg)
-{
- this->do_set_recover_arg(arg);
-}
-
-// Virtual functions also implemented by Builtin_call_expression.
-
-bool
-Call_expression::do_is_recover_call() const
-{
- return false;
-}
-
-void
-Call_expression::do_set_recover_arg(Expression*)
-{
- go_unreachable();
-}
-
-// We have found an error with this call expression; return true if
-// we should report it.
-
-bool
-Call_expression::issue_error()
-{
- if (this->issued_error_)
- return false;
- else
- {
- this->issued_error_ = true;
- return true;
- }
-}
-
-// Get the type.
-
-Type*
-Call_expression::do_type()
-{
- if (this->type_ != NULL)
- return this->type_;
-
- Type* ret;
- Function_type* fntype = this->get_function_type();
- if (fntype == NULL)
- return Type::make_error_type();
-
- const Typed_identifier_list* results = fntype->results();
- if (results == NULL)
- ret = Type::make_void_type();
- else if (results->size() == 1)
- ret = results->begin()->type();
- else
- ret = Type::make_call_multiple_result_type(this);
-
- this->type_ = ret;
-
- return this->type_;
-}
-
-// Determine types for a call expression. We can use the function
-// parameter types to set the types of the arguments.
-
-void
-Call_expression::do_determine_type(const Type_context*)
-{
- if (!this->determining_types())
- return;
-
- this->fn_->determine_type_no_context();
- Function_type* fntype = this->get_function_type();
- const Typed_identifier_list* parameters = NULL;
- if (fntype != NULL)
- parameters = fntype->parameters();
- if (this->args_ != NULL)
- {
- Typed_identifier_list::const_iterator pt;
- if (parameters != NULL)
- pt = parameters->begin();
- bool first = true;
- for (Expression_list::const_iterator pa = this->args_->begin();
- pa != this->args_->end();
- ++pa)
- {
- if (first)
- {
- first = false;
- // If this is a method, the first argument is the
- // receiver.
- if (fntype != NULL && fntype->is_method())
- {
- Type* rtype = fntype->receiver()->type();
- // The receiver is always passed as a pointer.
- if (rtype->points_to() == NULL)
- rtype = Type::make_pointer_type(rtype);
- Type_context subcontext(rtype, false);
- (*pa)->determine_type(&subcontext);
- continue;
- }
- }
-
- if (parameters != NULL && pt != parameters->end())
- {
- Type_context subcontext(pt->type(), false);
- (*pa)->determine_type(&subcontext);
- ++pt;
- }
- else
- (*pa)->determine_type_no_context();
- }
- }
-}
-
-// Called when determining types for a Call_expression. Return true
-// if we should go ahead, false if they have already been determined.
-
-bool
-Call_expression::determining_types()
-{
- if (this->types_are_determined_)
- return false;
- else
- {
- this->types_are_determined_ = true;
- return true;
- }
-}
-
-// Check types for parameter I.
-
-bool
-Call_expression::check_argument_type(int i, const Type* parameter_type,
- const Type* argument_type,
- Location argument_location,
- bool issued_error)
-{
- std::string reason;
- bool ok;
- if (this->are_hidden_fields_ok_)
- ok = Type::are_assignable_hidden_ok(parameter_type, argument_type,
- &reason);
- else
- ok = Type::are_assignable(parameter_type, argument_type, &reason);
- if (!ok)
- {
- if (!issued_error)
- {
- if (reason.empty())
- error_at(argument_location, "argument %d has incompatible type", i);
- else
- error_at(argument_location,
- "argument %d has incompatible type (%s)",
- i, reason.c_str());
- }
- this->set_is_error();
- return false;
- }
- return true;
-}
-
-// Check types.
-
-void
-Call_expression::do_check_types(Gogo*)
-{
- if (this->classification() == EXPRESSION_ERROR)
- return;
-
- Function_type* fntype = this->get_function_type();
- if (fntype == NULL)
- {
- if (!this->fn_->type()->is_error())
- this->report_error(_("expected function"));
- return;
- }
-
- bool is_method = fntype->is_method();
- if (is_method)
- {
- go_assert(this->args_ != NULL && !this->args_->empty());
- Type* rtype = fntype->receiver()->type();
- Expression* first_arg = this->args_->front();
- // The language permits copying hidden fields for a method
- // receiver. We dereference the values since receivers are
- // always passed as pointers.
- std::string reason;
- if (!Type::are_assignable_hidden_ok(rtype->deref(),
- first_arg->type()->deref(),
- &reason))
- {
- if (reason.empty())
- this->report_error(_("incompatible type for receiver"));
- else
- {
- error_at(this->location(),
- "incompatible type for receiver (%s)",
- reason.c_str());
- this->set_is_error();
- }
- }
- }
-
- // Note that varargs was handled by the lower_varargs() method, so
- // we don't have to worry about it here unless something is wrong.
- if (this->is_varargs_ && !this->varargs_are_lowered_)
- {
- if (!fntype->is_varargs())
- {
- error_at(this->location(),
- _("invalid use of %<...%> calling non-variadic function"));
- this->set_is_error();
- return;
- }
- }
-
- const Typed_identifier_list* parameters = fntype->parameters();
- if (this->args_ == NULL)
- {
- if (parameters != NULL && !parameters->empty())
- this->report_error(_("not enough arguments"));
- }
- else if (parameters == NULL)
- {
- if (!is_method || this->args_->size() > 1)
- this->report_error(_("too many arguments"));
- }
- else
- {
- int i = 0;
- Expression_list::const_iterator pa = this->args_->begin();
- if (is_method)
- ++pa;
- for (Typed_identifier_list::const_iterator pt = parameters->begin();
- pt != parameters->end();
- ++pt, ++pa, ++i)
- {
- if (pa == this->args_->end())
- {
- this->report_error(_("not enough arguments"));
- return;
- }
- this->check_argument_type(i + 1, pt->type(), (*pa)->type(),
- (*pa)->location(), false);
- }
- if (pa != this->args_->end())
- this->report_error(_("too many arguments"));
- }
-}
-
-// Return whether we have to use a temporary variable to ensure that
-// we evaluate this call expression in order. If the call returns no
-// results then it will inevitably be executed last.
-
-bool
-Call_expression::do_must_eval_in_order() const
-{
- return this->result_count() > 0;
-}
-
-// Get the function and the first argument to use when calling an
-// interface method.
-
-tree
-Call_expression::interface_method_function(
- Translate_context* context,
- Interface_field_reference_expression* interface_method,
- tree* first_arg_ptr)
-{
- tree expr = interface_method->expr()->get_tree(context);
- if (expr == error_mark_node)
- return error_mark_node;
- expr = save_expr(expr);
- tree first_arg = interface_method->get_underlying_object_tree(context, expr);
- if (first_arg == error_mark_node)
- return error_mark_node;
- *first_arg_ptr = first_arg;
- return interface_method->get_function_tree(context, expr);
-}
-
-// Build the call expression.
-
-tree
-Call_expression::do_get_tree(Translate_context* context)
-{
- if (this->tree_ != NULL_TREE)
- return this->tree_;
-
- Function_type* fntype = this->get_function_type();
- if (fntype == NULL)
- return error_mark_node;
-
- if (this->fn_->is_error_expression())
- return error_mark_node;
-
- Gogo* gogo = context->gogo();
- Location location = this->location();
-
- Func_expression* func = this->fn_->func_expression();
- Interface_field_reference_expression* interface_method =
- this->fn_->interface_field_reference_expression();
- const bool has_closure = func != NULL && func->closure() != NULL;
- const bool is_interface_method = interface_method != NULL;
-
- int nargs;
- tree* args;
- if (this->args_ == NULL || this->args_->empty())
- {
- nargs = is_interface_method ? 1 : 0;
- args = nargs == 0 ? NULL : new tree[nargs];
- }
- else if (fntype->parameters() == NULL || fntype->parameters()->empty())
- {
- // Passing a receiver parameter.
- go_assert(!is_interface_method
- && fntype->is_method()
- && this->args_->size() == 1);
- nargs = 1;
- args = new tree[nargs];
- args[0] = this->args_->front()->get_tree(context);
- }
- else
- {
- const Typed_identifier_list* params = fntype->parameters();
-
- nargs = this->args_->size();
- int i = is_interface_method ? 1 : 0;
- nargs += i;
- args = new tree[nargs];
-
- Typed_identifier_list::const_iterator pp = params->begin();
- Expression_list::const_iterator pe = this->args_->begin();
- if (!is_interface_method && fntype->is_method())
- {
- args[i] = (*pe)->get_tree(context);
- ++pe;
- ++i;
- }
- for (; pe != this->args_->end(); ++pe, ++pp, ++i)
- {
- go_assert(pp != params->end());
- tree arg_val = (*pe)->get_tree(context);
- args[i] = Expression::convert_for_assignment(context,
- pp->type(),
- (*pe)->type(),
- arg_val,
- location);
- if (args[i] == error_mark_node)
- {
- delete[] args;
- return error_mark_node;
- }
- }
- go_assert(pp == params->end());
- go_assert(i == nargs);
- }
-
- tree rettype = TREE_TYPE(TREE_TYPE(type_to_tree(fntype->get_backend(gogo))));
- if (rettype == error_mark_node)
- {
- delete[] args;
- return error_mark_node;
- }
-
- tree fn;
- if (has_closure)
- fn = func->get_tree_without_closure(gogo);
- else if (!is_interface_method)
- fn = this->fn_->get_tree(context);
- else
- fn = this->interface_method_function(context, interface_method, &args[0]);
-
- if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
- {
- delete[] args;
- return error_mark_node;
- }
-
- tree fndecl = fn;
- if (TREE_CODE(fndecl) == ADDR_EXPR)
- fndecl = TREE_OPERAND(fndecl, 0);
-
- // Add a type cast in case the type of the function is a recursive
- // type which refers to itself.
- if (!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl))
- {
- tree fnt = type_to_tree(fntype->get_backend(gogo));
- if (fnt == error_mark_node)
- return error_mark_node;
- fn = fold_convert_loc(location.gcc_location(), fnt, fn);
- }
-
- // This is to support builtin math functions when using 80387 math.
- tree excess_type = NULL_TREE;
- if (optimize
- && TREE_CODE(fndecl) == FUNCTION_DECL
- && DECL_IS_BUILTIN(fndecl)
- && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
- && nargs > 0
- && ((SCALAR_FLOAT_TYPE_P(rettype)
- && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0])))
- || (COMPLEX_FLOAT_TYPE_P(rettype)
- && COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[0])))))
- {
- excess_type = excess_precision_type(TREE_TYPE(args[0]));
- if (excess_type != NULL_TREE)
- {
- tree excess_fndecl = mathfn_built_in(excess_type,
- DECL_FUNCTION_CODE(fndecl));
- if (excess_fndecl == NULL_TREE)
- excess_type = NULL_TREE;
- else
- {
- fn = build_fold_addr_expr_loc(location.gcc_location(),
- excess_fndecl);
- for (int i = 0; i < nargs; ++i)
- {
- if (SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[i]))
- || COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[i])))
- args[i] = ::convert(excess_type, args[i]);
- }
- }
- }
- }
-
- if (func == NULL)
- fn = save_expr(fn);
-
- tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype,
- fn, nargs, args);
- delete[] args;
-
- SET_EXPR_LOCATION(ret, location.gcc_location());
-
- if (has_closure)
- {
- tree closure_tree = func->closure()->get_tree(context);
- if (closure_tree != error_mark_node)
- 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 = type_to_tree(this->type()->base()->get_backend(gogo));
- ret = fold_convert_loc(location.gcc_location(), t, ret);
- }
-
- if (excess_type != NULL_TREE)
- {
- // Calling convert here can undo our excess precision change.
- // That may or may not be a bug in convert_to_real.
- ret = build1(NOP_EXPR, rettype, ret);
- }
-
- if (this->results_ != NULL)
- ret = this->set_results(context, ret);
-
- // We can't unwind the stack past a call to nil, so we need to
- // insert an explicit check so that the panic can be recovered.
- if (func == NULL)
- {
- tree compare = fold_build2_loc(location.gcc_location(), EQ_EXPR,
- boolean_type_node, fn,
- fold_convert_loc(location.gcc_location(),
- TREE_TYPE(fn),
- null_pointer_node));
- tree crash = build3_loc(location.gcc_location(), COND_EXPR,
- void_type_node, compare,
- gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
- location),
- NULL_TREE);
- ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(ret), crash, ret);
- }
-
- this->tree_ = ret;
-
- return ret;
-}
-
-// Set the result variables if this call returns multiple results.
-
-tree
-Call_expression::set_results(Translate_context* context, tree call_tree)
-{
- tree stmt_list = NULL_TREE;
-
- call_tree = save_expr(call_tree);
-
- if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE)
- {
- go_assert(saw_errors());
- return call_tree;
- }
-
- Location loc = this->location();
- tree field = TYPE_FIELDS(TREE_TYPE(call_tree));
- size_t rc = this->result_count();
- for (size_t i = 0; i < rc; ++i, field = DECL_CHAIN(field))
- {
- go_assert(field != NULL_TREE);
-
- Temporary_statement* temp = this->result(i);
- if (temp == NULL)
- {
- go_assert(saw_errors());
- return error_mark_node;
- }
- Temporary_reference_expression* ref =
- Expression::make_temporary_reference(temp, loc);
- ref->set_is_lvalue();
- tree temp_tree = ref->get_tree(context);
- if (temp_tree == error_mark_node)
- return error_mark_node;
-
- tree val_tree = build3_loc(loc.gcc_location(), COMPONENT_REF,
- TREE_TYPE(field), call_tree, field, NULL_TREE);
- tree set_tree = build2_loc(loc.gcc_location(), MODIFY_EXPR,
- void_type_node, temp_tree, val_tree);
-
- append_to_statement_list(set_tree, &stmt_list);
- }
- go_assert(field == NULL_TREE);
-
- return save_expr(stmt_list);
-}
-
-// Dump ast representation for a call expressin.
-
-void
-Call_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- this->fn_->dump_expression(ast_dump_context);
- ast_dump_context->ostream() << "(";
- if (args_ != NULL)
- ast_dump_context->dump_expression_list(this->args_);
-
- ast_dump_context->ostream() << ") ";
-}
-
-// Make a call expression.
-
-Call_expression*
-Expression::make_call(Expression* fn, Expression_list* args, bool is_varargs,
- Location location)
-{
- return new Call_expression(fn, args, is_varargs, location);
-}
-
-// A single result from a call which returns multiple results.
-
-class Call_result_expression : public Expression
-{
- public:
- Call_result_expression(Call_expression* call, unsigned int index)
- : Expression(EXPRESSION_CALL_RESULT, call->location()),
- call_(call), index_(index)
- { }
-
- protected:
- int
- do_traverse(Traverse*);
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return new Call_result_expression(this->call_->call_expression(),
- this->index_);
- }
-
- bool
- do_must_eval_in_order() const
- { return true; }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The underlying call expression.
- Expression* call_;
- // Which result we want.
- unsigned int index_;
-};
-
-// Traverse a call result.
-
-int
-Call_result_expression::do_traverse(Traverse* traverse)
-{
- if (traverse->remember_expression(this->call_))
- {
- // We have already traversed the call expression.
- return TRAVERSE_CONTINUE;
- }
- return Expression::traverse(&this->call_, traverse);
-}
-
-// Get the type.
-
-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();
- if (ce == NULL)
- {
- this->set_is_error();
- return Type::make_error_type();
- }
- Function_type* fntype = ce->get_function_type();
- if (fntype == NULL)
- {
- if (ce->issue_error())
- {
- if (!ce->fn()->type()->is_error())
- this->report_error(_("expected function"));
- }
- this->set_is_error();
- return Type::make_error_type();
- }
- const Typed_identifier_list* results = fntype->results();
- if (results == NULL || results->size() < 2)
- {
- if (ce->issue_error())
- this->report_error(_("number of results does not match "
- "number of values"));
- return Type::make_error_type();
- }
- Typed_identifier_list::const_iterator pr = results->begin();
- for (unsigned int i = 0; i < this->index_; ++i)
- {
- if (pr == results->end())
- break;
- ++pr;
- }
- if (pr == results->end())
- {
- if (ce->issue_error())
- this->report_error(_("number of results does not match "
- "number of values"));
- return Type::make_error_type();
- }
- return pr->type();
-}
-
-// Check the type. Just make sure that we trigger the warning in
-// do_type.
-
-void
-Call_result_expression::do_check_types(Gogo*)
-{
- this->type();
-}
-
-// Determine the type. We have nothing to do here, but the 0 result
-// needs to pass down to the caller.
-
-void
-Call_result_expression::do_determine_type(const Type_context*)
-{
- this->call_->determine_type_no_context();
-}
-
-// Return the tree. We just refer to the temporary set by the call
-// expression. We don't do this at lowering time because it makes it
-// hard to evaluate the call at the right time.
-
-tree
-Call_result_expression::do_get_tree(Translate_context* context)
-{
- Call_expression* ce = this->call_->call_expression();
- if (ce == NULL)
- {
- go_assert(this->call_->is_error_expression());
- return error_mark_node;
- }
- Temporary_statement* ts = ce->result(this->index_);
- if (ts == NULL)
- {
- go_assert(saw_errors());
- return error_mark_node;
- }
- Expression* ref = Expression::make_temporary_reference(ts, this->location());
- return ref->get_tree(context);
-}
-
-// Dump ast representation for a call result expression.
-
-void
-Call_result_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
- const
-{
- // FIXME: Wouldn't it be better if the call is assigned to a temporary
- // (struct) and the fields are referenced instead.
- ast_dump_context->ostream() << this->index_ << "@(";
- ast_dump_context->dump_expression(this->call_);
- ast_dump_context->ostream() << ")";
-}
-
-// Make a reference to a single result of a call which returns
-// multiple results.
-
-Expression*
-Expression::make_call_result(Call_expression* call, unsigned int index)
-{
- return new Call_result_expression(call, index);
-}
-
-// Class Index_expression.
-
-// Traversal.
-
-int
-Index_expression::do_traverse(Traverse* traverse)
-{
- if (Expression::traverse(&this->left_, traverse) == TRAVERSE_EXIT
- || Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT
- || (this->end_ != NULL
- && Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT))
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Lower an index expression. This converts the generic index
-// expression into an array index, a string index, or a map index.
-
-Expression*
-Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
-{
- Location location = this->location();
- Expression* left = this->left_;
- Expression* start = this->start_;
- Expression* end = this->end_;
-
- Type* type = left->type();
- if (type->is_error())
- return Expression::make_error(location);
- else if (left->is_type_expression())
- {
- error_at(location, "attempt to index type expression");
- return Expression::make_error(location);
- }
- else if (type->array_type() != NULL)
- return Expression::make_array_index(left, start, end, location);
- else if (type->points_to() != NULL
- && type->points_to()->array_type() != NULL
- && !type->points_to()->is_slice_type())
- {
- Expression* deref = Expression::make_unary(OPERATOR_MULT, left,
- location);
- return Expression::make_array_index(deref, start, end, location);
- }
- else if (type->is_string_type())
- return Expression::make_string_index(left, start, end, location);
- else if (type->map_type() != NULL)
- {
- if (end != NULL)
- {
- error_at(location, "invalid slice of map");
- return Expression::make_error(location);
- }
- Map_index_expression* ret = Expression::make_map_index(left, start,
- location);
- if (this->is_lvalue_)
- ret->set_is_lvalue();
- return ret;
- }
- else
- {
- error_at(location,
- "attempt to index object which is not array, string, or map");
- return Expression::make_error(location);
- }
-}
-
-// Write an indexed expression (expr[expr:expr] or expr[expr]) to a
-// dump context
-
-void
-Index_expression::dump_index_expression(Ast_dump_context* ast_dump_context,
- const Expression* expr,
- const Expression* start,
- const Expression* end)
-{
- expr->dump_expression(ast_dump_context);
- ast_dump_context->ostream() << "[";
- start->dump_expression(ast_dump_context);
- if (end != NULL)
- {
- ast_dump_context->ostream() << ":";
- end->dump_expression(ast_dump_context);
- }
- ast_dump_context->ostream() << "]";
-}
-
-// Dump ast representation for an index expression.
-
-void
-Index_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
- const
-{
- Index_expression::dump_index_expression(ast_dump_context, this->left_,
- this->start_, this->end_);
-}
-
-// Make an index expression.
-
-Expression*
-Expression::make_index(Expression* left, Expression* start, Expression* end,
- Location location)
-{
- return new Index_expression(left, start, end, location);
-}
-
-// An array index. This is used for both indexing and slicing.
-
-class Array_index_expression : public Expression
-{
- public:
- Array_index_expression(Expression* array, Expression* start,
- Expression* end, Location location)
- : Expression(EXPRESSION_ARRAY_INDEX, location),
- array_(array), start_(start), end_(end), type_(NULL)
- { }
-
- protected:
- int
- do_traverse(Traverse*);
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_array_index(this->array_->copy(),
- this->start_->copy(),
- (this->end_ == NULL
- ? NULL
- : this->end_->copy()),
- this->location());
- }
-
- bool
- do_must_eval_subexpressions_in_order(int* skip) const
- {
- *skip = 1;
- return true;
- }
-
- bool
- do_is_addressable() const;
-
- void
- do_address_taken(bool escapes)
- { this->array_->address_taken(escapes); }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The array we are getting a value from.
- Expression* array_;
- // The start or only index.
- Expression* start_;
- // The end index of a slice. This may be NULL for a simple array
- // index, or it may be a nil expression for the length of the array.
- Expression* end_;
- // The type of the expression.
- Type* type_;
-};
-
-// Array index traversal.
-
-int
-Array_index_expression::do_traverse(Traverse* traverse)
-{
- if (Expression::traverse(&this->array_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (this->end_ != NULL)
- {
- if (Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Return the type of an array index.
-
-Type*
-Array_index_expression::do_type()
-{
- if (this->type_ == NULL)
- {
- Array_type* type = this->array_->type()->array_type();
- if (type == NULL)
- this->type_ = Type::make_error_type();
- else if (this->end_ == NULL)
- this->type_ = type->element_type();
- else if (type->is_slice_type())
- {
- // A slice of a slice has the same type as the original
- // slice.
- this->type_ = this->array_->type()->deref();
- }
- else
- {
- // A slice of an array is a slice.
- this->type_ = Type::make_array_type(type->element_type(), NULL);
- }
- }
- return this->type_;
-}
-
-// Set the type of an array index.
-
-void
-Array_index_expression::do_determine_type(const Type_context*)
-{
- this->array_->determine_type_no_context();
- this->start_->determine_type_no_context();
- if (this->end_ != NULL)
- this->end_->determine_type_no_context();
-}
-
-// Check types of an array index.
-
-void
-Array_index_expression::do_check_types(Gogo*)
-{
- if (this->start_->type()->integer_type() == NULL)
- this->report_error(_("index must be integer"));
- if (this->end_ != NULL
- && this->end_->type()->integer_type() == NULL
- && !this->end_->type()->is_error()
- && !this->end_->is_nil_expression()
- && !this->end_->is_error_expression())
- this->report_error(_("slice end must be integer"));
-
- Array_type* array_type = this->array_->type()->array_type();
- if (array_type == NULL)
- {
- go_assert(this->array_->type()->is_error());
- return;
- }
-
- unsigned int int_bits =
- Type::lookup_integer_type("int")->integer_type()->bits();
-
- Numeric_constant lvalnc;
- mpz_t lval;
- bool lval_valid = (array_type->length() != NULL
- && array_type->length()->numeric_constant_value(&lvalnc)
- && lvalnc.to_int(&lval));
- Numeric_constant inc;
- mpz_t ival;
- bool ival_valid = false;
- if (this->start_->numeric_constant_value(&inc) && inc.to_int(&ival))
- {
- ival_valid = true;
- if (mpz_sgn(ival) < 0
- || mpz_sizeinbase(ival, 2) >= int_bits
- || (lval_valid
- && (this->end_ == NULL
- ? mpz_cmp(ival, lval) >= 0
- : mpz_cmp(ival, lval) > 0)))
- {
- error_at(this->start_->location(), "array index out of bounds");
- this->set_is_error();
- }
- }
- if (this->end_ != NULL && !this->end_->is_nil_expression())
- {
- Numeric_constant enc;
- mpz_t eval;
- if (this->end_->numeric_constant_value(&enc) && enc.to_int(&eval))
- {
- if (mpz_sgn(eval) < 0
- || mpz_sizeinbase(eval, 2) >= int_bits
- || (lval_valid && mpz_cmp(eval, lval) > 0))
- {
- error_at(this->end_->location(), "array index out of bounds");
- this->set_is_error();
- }
- else if (ival_valid && mpz_cmp(ival, eval) > 0)
- this->report_error(_("inverted slice range"));
- mpz_clear(eval);
- }
- }
- if (ival_valid)
- mpz_clear(ival);
- if (lval_valid)
- mpz_clear(lval);
-
- // A slice of an array requires an addressable array. A slice of a
- // slice is always possible.
- if (this->end_ != NULL && !array_type->is_slice_type())
- {
- if (!this->array_->is_addressable())
- this->report_error(_("slice of unaddressable value"));
- else
- this->array_->address_taken(true);
- }
-}
-
-// Return whether this expression is addressable.
-
-bool
-Array_index_expression::do_is_addressable() const
-{
- // A slice expression is not addressable.
- if (this->end_ != NULL)
- return false;
-
- // An index into a slice is addressable.
- if (this->array_->type()->is_slice_type())
- return true;
-
- // An index into an array is addressable if the array is
- // addressable.
- return this->array_->is_addressable();
-}
-
-// Get a tree for an array index.
-
-tree
-Array_index_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
- Location loc = this->location();
-
- Array_type* array_type = this->array_->type()->array_type();
- if (array_type == NULL)
- {
- go_assert(this->array_->type()->is_error());
- return error_mark_node;
- }
-
- tree type_tree = type_to_tree(array_type->get_backend(gogo));
- if (type_tree == error_mark_node)
- return error_mark_node;
-
- tree array_tree = this->array_->get_tree(context);
- if (array_tree == error_mark_node)
- return error_mark_node;
-
- if (array_type->length() == NULL && !DECL_P(array_tree))
- array_tree = save_expr(array_tree);
-
- tree length_tree = NULL_TREE;
- if (this->end_ == NULL || this->end_->is_nil_expression())
- {
- length_tree = array_type->length_tree(gogo, array_tree);
- if (length_tree == error_mark_node)
- return error_mark_node;
- length_tree = save_expr(length_tree);
- }
-
- tree capacity_tree = NULL_TREE;
- if (this->end_ != NULL)
- {
- capacity_tree = array_type->capacity_tree(gogo, array_tree);
- if (capacity_tree == error_mark_node)
- return error_mark_node;
- capacity_tree = save_expr(capacity_tree);
- }
-
- tree length_type = (length_tree != NULL_TREE
- ? TREE_TYPE(length_tree)
- : TREE_TYPE(capacity_tree));
-
- tree bad_index = boolean_false_node;
-
- tree start_tree = this->start_->get_tree(context);
- if (start_tree == error_mark_node)
- return error_mark_node;
- if (!DECL_P(start_tree))
- start_tree = save_expr(start_tree);
- if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree)))
- start_tree = convert_to_integer(length_type, start_tree);
-
- bad_index = Expression::check_bounds(start_tree, length_type, bad_index,
- loc);
-
- start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree);
- bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, bad_index,
- fold_build2_loc(loc.gcc_location(),
- (this->end_ == NULL
- ? GE_EXPR
- : GT_EXPR),
- boolean_type_node, start_tree,
- (this->end_ == NULL
- ? length_tree
- : capacity_tree)));
-
- int code = (array_type->length() != NULL
- ? (this->end_ == NULL
- ? RUNTIME_ERROR_ARRAY_INDEX_OUT_OF_BOUNDS
- : RUNTIME_ERROR_ARRAY_SLICE_OUT_OF_BOUNDS)
- : (this->end_ == NULL
- ? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS
- : RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS));
- tree crash = gogo->runtime_error(code, loc);
-
- if (this->end_ == NULL)
- {
- // Simple array indexing. This has to return an l-value, so
- // wrap the index check into START_TREE.
- start_tree = build2(COMPOUND_EXPR, TREE_TYPE(start_tree),
- build3(COND_EXPR, void_type_node,
- bad_index, crash, NULL_TREE),
- start_tree);
- start_tree = fold_convert_loc(loc.gcc_location(), sizetype, start_tree);
-
- if (array_type->length() != NULL)
- {
- // Fixed array.
- return build4(ARRAY_REF, TREE_TYPE(type_tree), array_tree,
- start_tree, NULL_TREE, NULL_TREE);
- }
- else
- {
- // Open array.
- tree values = array_type->value_pointer_tree(gogo, array_tree);
- Type* element_type = array_type->element_type();
- Btype* belement_type = element_type->get_backend(gogo);
- tree element_type_tree = type_to_tree(belement_type);
- if (element_type_tree == error_mark_node)
- return error_mark_node;
- tree element_size = TYPE_SIZE_UNIT(element_type_tree);
- tree offset = fold_build2_loc(loc.gcc_location(), MULT_EXPR, sizetype,
- start_tree, element_size);
- tree ptr = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR,
- TREE_TYPE(values), values, offset);
- return build_fold_indirect_ref(ptr);
- }
- }
-
- // Array slice.
-
- tree end_tree;
- if (this->end_->is_nil_expression())
- end_tree = length_tree;
- else
- {
- end_tree = this->end_->get_tree(context);
- if (end_tree == error_mark_node)
- return error_mark_node;
- if (!DECL_P(end_tree))
- end_tree = save_expr(end_tree);
- if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree)))
- end_tree = convert_to_integer(length_type, end_tree);
-
- bad_index = Expression::check_bounds(end_tree, length_type, bad_index,
- loc);
-
- end_tree = fold_convert_loc(loc.gcc_location(), length_type, end_tree);
-
- tree bad_end = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node,
- fold_build2_loc(loc.gcc_location(),
- LT_EXPR, boolean_type_node,
- end_tree, start_tree),
- fold_build2_loc(loc.gcc_location(),
- GT_EXPR, boolean_type_node,
- end_tree, capacity_tree));
- bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, bad_index, bad_end);
- }
-
- Type* element_type = array_type->element_type();
- tree element_type_tree = type_to_tree(element_type->get_backend(gogo));
- if (element_type_tree == error_mark_node)
- return error_mark_node;
- tree element_size = TYPE_SIZE_UNIT(element_type_tree);
-
- tree offset = fold_build2_loc(loc.gcc_location(), MULT_EXPR, sizetype,
- fold_convert_loc(loc.gcc_location(), sizetype,
- start_tree),
- element_size);
-
- tree value_pointer = array_type->value_pointer_tree(gogo, array_tree);
- if (value_pointer == error_mark_node)
- return error_mark_node;
-
- value_pointer = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR,
- TREE_TYPE(value_pointer),
- value_pointer, offset);
-
- tree result_length_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR,
- length_type, end_tree, start_tree);
-
- tree result_capacity_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR,
- length_type, capacity_tree,
- start_tree);
-
- tree struct_tree = type_to_tree(this->type()->get_backend(gogo));
- go_assert(TREE_CODE(struct_tree) == RECORD_TYPE);
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc (init, 3);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(struct_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
- elt->index = field;
- elt->value = value_pointer;
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
- elt->index = field;
- elt->value = fold_convert_loc(loc.gcc_location(), TREE_TYPE(field),
- result_length_tree);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
- elt->index = field;
- elt->value = fold_convert_loc(loc.gcc_location(), TREE_TYPE(field),
- result_capacity_tree);
-
- tree constructor = build_constructor(struct_tree, init);
-
- if (TREE_CONSTANT(value_pointer)
- && TREE_CONSTANT(result_length_tree)
- && TREE_CONSTANT(result_capacity_tree))
- TREE_CONSTANT(constructor) = 1;
-
- return fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(constructor),
- build3(COND_EXPR, void_type_node,
- bad_index, crash, NULL_TREE),
- constructor);
-}
-
-// Dump ast representation for an array index expression.
-
-void
-Array_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
- const
-{
- Index_expression::dump_index_expression(ast_dump_context, this->array_,
- this->start_, this->end_);
-}
-
-// Make an array index expression. END may be NULL.
-
-Expression*
-Expression::make_array_index(Expression* array, Expression* start,
- Expression* end, Location location)
-{
- return new Array_index_expression(array, start, end, location);
-}
-
-// A string index. This is used for both indexing and slicing.
-
-class String_index_expression : public Expression
-{
- public:
- String_index_expression(Expression* string, Expression* start,
- Expression* end, Location location)
- : Expression(EXPRESSION_STRING_INDEX, location),
- string_(string), start_(start), end_(end)
- { }
-
- protected:
- int
- do_traverse(Traverse*);
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_string_index(this->string_->copy(),
- this->start_->copy(),
- (this->end_ == NULL
- ? NULL
- : this->end_->copy()),
- this->location());
- }
-
- bool
- do_must_eval_subexpressions_in_order(int* skip) const
- {
- *skip = 1;
- return true;
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The string we are getting a value from.
- Expression* string_;
- // The start or only index.
- Expression* start_;
- // The end index of a slice. This may be NULL for a single index,
- // or it may be a nil expression for the length of the string.
- Expression* end_;
-};
-
-// String index traversal.
-
-int
-String_index_expression::do_traverse(Traverse* traverse)
-{
- if (Expression::traverse(&this->string_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (this->end_ != NULL)
- {
- if (Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Return the type of a string index.
-
-Type*
-String_index_expression::do_type()
-{
- if (this->end_ == NULL)
- return Type::lookup_integer_type("uint8");
- else
- return this->string_->type();
-}
-
-// Determine the type of a string index.
-
-void
-String_index_expression::do_determine_type(const Type_context*)
-{
- this->string_->determine_type_no_context();
- this->start_->determine_type_no_context();
- if (this->end_ != NULL)
- this->end_->determine_type_no_context();
-}
-
-// Check types of a string index.
-
-void
-String_index_expression::do_check_types(Gogo*)
-{
- if (this->start_->type()->integer_type() == NULL)
- this->report_error(_("index must be integer"));
- if (this->end_ != NULL
- && this->end_->type()->integer_type() == NULL
- && !this->end_->is_nil_expression())
- this->report_error(_("slice end must be integer"));
-
- std::string sval;
- bool sval_valid = this->string_->string_constant_value(&sval);
-
- Numeric_constant inc;
- mpz_t ival;
- bool ival_valid = false;
- if (this->start_->numeric_constant_value(&inc) && inc.to_int(&ival))
- {
- ival_valid = true;
- if (mpz_sgn(ival) < 0
- || (sval_valid && mpz_cmp_ui(ival, sval.length()) >= 0))
- {
- error_at(this->start_->location(), "string index out of bounds");
- this->set_is_error();
- }
- }
- if (this->end_ != NULL && !this->end_->is_nil_expression())
- {
- Numeric_constant enc;
- mpz_t eval;
- if (this->end_->numeric_constant_value(&enc) && enc.to_int(&eval))
- {
- if (mpz_sgn(eval) < 0
- || (sval_valid && mpz_cmp_ui(eval, sval.length()) > 0))
- {
- error_at(this->end_->location(), "string index out of bounds");
- this->set_is_error();
- }
- else if (ival_valid && mpz_cmp(ival, eval) > 0)
- this->report_error(_("inverted slice range"));
- mpz_clear(eval);
- }
- }
- if (ival_valid)
- mpz_clear(ival);
-}
-
-// Get a tree for a string index.
-
-tree
-String_index_expression::do_get_tree(Translate_context* context)
-{
- Location loc = this->location();
-
- tree string_tree = this->string_->get_tree(context);
- if (string_tree == error_mark_node)
- return error_mark_node;
-
- if (this->string_->type()->points_to() != NULL)
- string_tree = build_fold_indirect_ref(string_tree);
- if (!DECL_P(string_tree))
- string_tree = save_expr(string_tree);
- tree string_type = TREE_TYPE(string_tree);
-
- tree length_tree = String_type::length_tree(context->gogo(), string_tree);
- length_tree = save_expr(length_tree);
-
- Type* int_type = Type::lookup_integer_type("int");
- tree length_type = type_to_tree(int_type->get_backend(context->gogo()));
-
- tree bad_index = boolean_false_node;
-
- tree start_tree = this->start_->get_tree(context);
- if (start_tree == error_mark_node)
- return error_mark_node;
- if (!DECL_P(start_tree))
- start_tree = save_expr(start_tree);
- if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree)))
- start_tree = convert_to_integer(length_type, start_tree);
-
- bad_index = Expression::check_bounds(start_tree, length_type, bad_index,
- loc);
-
- start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree);
-
- int code = (this->end_ == NULL
- ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS
- : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS);
- tree crash = context->gogo()->runtime_error(code, loc);
-
- if (this->end_ == NULL)
- {
- bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, bad_index,
- fold_build2_loc(loc.gcc_location(), GE_EXPR,
- boolean_type_node,
- start_tree, length_tree));
-
- tree bytes_tree = String_type::bytes_tree(context->gogo(), string_tree);
- tree ptr = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR,
- TREE_TYPE(bytes_tree),
- bytes_tree,
- fold_convert_loc(loc.gcc_location(), sizetype,
- start_tree));
- tree index = build_fold_indirect_ref_loc(loc.gcc_location(), ptr);
-
- return build2(COMPOUND_EXPR, TREE_TYPE(index),
- build3(COND_EXPR, void_type_node,
- bad_index, crash, NULL_TREE),
- index);
- }
- else
- {
- tree end_tree;
- if (this->end_->is_nil_expression())
- end_tree = build_int_cst(length_type, -1);
- else
- {
- end_tree = this->end_->get_tree(context);
- if (end_tree == error_mark_node)
- return error_mark_node;
- if (!DECL_P(end_tree))
- end_tree = save_expr(end_tree);
- if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree)))
- end_tree = convert_to_integer(length_type, end_tree);
-
- bad_index = Expression::check_bounds(end_tree, length_type,
- bad_index, loc);
-
- end_tree = fold_convert_loc(loc.gcc_location(), length_type,
- end_tree);
- }
-
- static tree strslice_fndecl;
- tree ret = Gogo::call_builtin(&strslice_fndecl,
- loc,
- "__go_string_slice",
- 3,
- string_type,
- string_type,
- string_tree,
- length_type,
- 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;
-
- if (bad_index == boolean_false_node)
- return ret;
- else
- return build2(COMPOUND_EXPR, TREE_TYPE(ret),
- build3(COND_EXPR, void_type_node,
- bad_index, crash, NULL_TREE),
- ret);
- }
-}
-
-// Dump ast representation for a string index expression.
-
-void
-String_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
- const
-{
- Index_expression::dump_index_expression(ast_dump_context, this->string_,
- this->start_, this->end_);
-}
-
-// Make a string index expression. END may be NULL.
-
-Expression*
-Expression::make_string_index(Expression* string, Expression* start,
- Expression* end, Location location)
-{
- return new String_index_expression(string, start, end, location);
-}
-
-// Class Map_index.
-
-// Get the type of the map.
-
-Map_type*
-Map_index_expression::get_map_type() const
-{
- Map_type* mt = this->map_->type()->deref()->map_type();
- if (mt == NULL)
- go_assert(saw_errors());
- return mt;
-}
-
-// Map index traversal.
-
-int
-Map_index_expression::do_traverse(Traverse* traverse)
-{
- if (Expression::traverse(&this->map_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return Expression::traverse(&this->index_, traverse);
-}
-
-// Return the type of a map index.
-
-Type*
-Map_index_expression::do_type()
-{
- Map_type* mt = this->get_map_type();
- if (mt == NULL)
- return Type::make_error_type();
- Type* type = mt->val_type();
- // If this map index is in a tuple assignment, we actually return a
- // pointer to the value type. Tuple_map_assignment_statement is
- // responsible for handling this correctly. We need to get the type
- // right in case this gets assigned to a temporary variable.
- if (this->is_in_tuple_assignment_)
- type = Type::make_pointer_type(type);
- return type;
-}
-
-// Fix the type of a map index.
-
-void
-Map_index_expression::do_determine_type(const Type_context*)
-{
- this->map_->determine_type_no_context();
- Map_type* mt = this->get_map_type();
- Type* key_type = mt == NULL ? NULL : mt->key_type();
- Type_context subcontext(key_type, false);
- this->index_->determine_type(&subcontext);
-}
-
-// Check types of a map index.
-
-void
-Map_index_expression::do_check_types(Gogo*)
-{
- std::string reason;
- Map_type* mt = this->get_map_type();
- if (mt == NULL)
- return;
- if (!Type::are_assignable(mt->key_type(), this->index_->type(), &reason))
- {
- if (reason.empty())
- this->report_error(_("incompatible type for map index"));
- else
- {
- error_at(this->location(), "incompatible type for map index (%s)",
- reason.c_str());
- this->set_is_error();
- }
- }
-}
-
-// Get a tree for a map index.
-
-tree
-Map_index_expression::do_get_tree(Translate_context* context)
-{
- Map_type* type = this->get_map_type();
- if (type == NULL)
- return error_mark_node;
-
- tree valptr = this->get_value_pointer(context, this->is_lvalue_);
- if (valptr == error_mark_node)
- return error_mark_node;
- valptr = save_expr(valptr);
-
- tree val_type_tree = TREE_TYPE(TREE_TYPE(valptr));
-
- if (this->is_lvalue_)
- return build_fold_indirect_ref(valptr);
- else if (this->is_in_tuple_assignment_)
- {
- // Tuple_map_assignment_statement is responsible for using this
- // appropriately.
- return valptr;
- }
- else
- {
- Gogo* gogo = context->gogo();
- Btype* val_btype = type->val_type()->get_backend(gogo);
- Bexpression* val_zero = gogo->backend()->zero_expression(val_btype);
- return fold_build3(COND_EXPR, val_type_tree,
- fold_build2(EQ_EXPR, boolean_type_node, valptr,
- fold_convert(TREE_TYPE(valptr),
- null_pointer_node)),
- expr_to_tree(val_zero),
- build_fold_indirect_ref(valptr));
- }
-}
-
-// Get a tree for the map index. This returns a tree which evaluates
-// to a pointer to a value. The pointer will be NULL if the key is
-// not in the map.
-
-tree
-Map_index_expression::get_value_pointer(Translate_context* context,
- bool insert)
-{
- Map_type* type = this->get_map_type();
- if (type == NULL)
- return error_mark_node;
-
- tree map_tree = this->map_->get_tree(context);
- tree index_tree = this->index_->get_tree(context);
- index_tree = Expression::convert_for_assignment(context, type->key_type(),
- this->index_->type(),
- index_tree,
- this->location());
- if (map_tree == error_mark_node || index_tree == error_mark_node)
- return error_mark_node;
-
- if (this->map_->type()->points_to() != NULL)
- map_tree = build_fold_indirect_ref(map_tree);
-
- // We need to pass in a pointer to the key, so stuff it into a
- // variable.
- tree tmp;
- tree make_tmp;
- if (current_function_decl != NULL)
- {
- tmp = create_tmp_var(TREE_TYPE(index_tree), get_name(index_tree));
- DECL_IGNORED_P(tmp) = 0;
- DECL_INITIAL(tmp) = index_tree;
- make_tmp = build1(DECL_EXPR, void_type_node, tmp);
- TREE_ADDRESSABLE(tmp) = 1;
- }
- else
- {
- tmp = build_decl(this->location().gcc_location(), VAR_DECL,
- create_tmp_var_name("M"),
- TREE_TYPE(index_tree));
- DECL_EXTERNAL(tmp) = 0;
- TREE_PUBLIC(tmp) = 0;
- TREE_STATIC(tmp) = 1;
- DECL_ARTIFICIAL(tmp) = 1;
- if (!TREE_CONSTANT(index_tree))
- make_tmp = fold_build2_loc(this->location().gcc_location(),
- INIT_EXPR, void_type_node,
- tmp, index_tree);
- else
- {
- TREE_READONLY(tmp) = 1;
- TREE_CONSTANT(tmp) = 1;
- DECL_INITIAL(tmp) = index_tree;
- make_tmp = NULL_TREE;
- }
- rest_of_decl_compilation(tmp, 1, 0);
- }
- tree tmpref =
- fold_convert_loc(this->location().gcc_location(), const_ptr_type_node,
- build_fold_addr_expr_loc(this->location().gcc_location(),
- tmp));
-
- static tree map_index_fndecl;
- tree call = Gogo::call_builtin(&map_index_fndecl,
- this->location(),
- "__go_map_index",
- 3,
- const_ptr_type_node,
- TREE_TYPE(map_tree),
- map_tree,
- const_ptr_type_node,
- tmpref,
- boolean_type_node,
- (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;
-
- Type* val_type = type->val_type();
- tree val_type_tree = type_to_tree(val_type->get_backend(context->gogo()));
- if (val_type_tree == error_mark_node)
- return error_mark_node;
- tree ptr_val_type_tree = build_pointer_type(val_type_tree);
-
- tree ret = fold_convert_loc(this->location().gcc_location(),
- ptr_val_type_tree, call);
- if (make_tmp != NULL_TREE)
- ret = build2(COMPOUND_EXPR, ptr_val_type_tree, make_tmp, ret);
- return ret;
-}
-
-// Dump ast representation for a map index expression
-
-void
-Map_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
- const
-{
- Index_expression::dump_index_expression(ast_dump_context,
- this->map_, this->index_, NULL);
-}
-
-// Make a map index expression.
-
-Map_index_expression*
-Expression::make_map_index(Expression* map, Expression* index,
- Location location)
-{
- return new Map_index_expression(map, index, location);
-}
-
-// Class Field_reference_expression.
-
-// Lower a field reference expression. There is nothing to lower, but
-// this is where we generate the tracking information for fields with
-// the magic go:"track" tag.
-
-Expression*
-Field_reference_expression::do_lower(Gogo* gogo, Named_object* function,
- Statement_inserter* inserter, int)
-{
- Struct_type* struct_type = this->expr_->type()->struct_type();
- if (struct_type == NULL)
- {
- // Error will be reported elsewhere.
- return this;
- }
- const Struct_field* field = struct_type->field(this->field_index_);
- if (field == NULL)
- return this;
- if (!field->has_tag())
- return this;
- if (field->tag().find("go:\"track\"") == std::string::npos)
- return this;
-
- // We have found a reference to a tracked field. Build a call to
- // the runtime function __go_fieldtrack with a string that describes
- // the field. FIXME: We should only call this once per referenced
- // field per function, not once for each reference to the field.
-
- if (this->called_fieldtrack_)
- return this;
- this->called_fieldtrack_ = true;
-
- Location loc = this->location();
-
- std::string s = "fieldtrack \"";
- Named_type* nt = this->expr_->type()->named_type();
- if (nt == NULL || nt->named_object()->package() == NULL)
- s.append(gogo->pkgpath());
- else
- s.append(nt->named_object()->package()->pkgpath());
- s.push_back('.');
- if (nt != NULL)
- s.append(Gogo::unpack_hidden_name(nt->name()));
- s.push_back('.');
- s.append(field->field_name());
- s.push_back('"');
-
- // We can't use a string here, because internally a string holds a
- // pointer to the actual bytes; when the linker garbage collects the
- // string, it won't garbage collect the bytes. So we use a
- // [...]byte.
-
- mpz_t val;
- mpz_init_set_ui(val, s.length());
- Expression* length_expr = Expression::make_integer(&val, NULL, loc);
- mpz_clear(val);
-
- Type* byte_type = gogo->lookup_global("byte")->type_value();
- Type* array_type = Type::make_array_type(byte_type, length_expr);
-
- Expression_list* bytes = new Expression_list();
- for (std::string::const_iterator p = s.begin(); p != s.end(); p++)
- {
- mpz_init_set_ui(val, *p);
- Expression* byte = Expression::make_integer(&val, NULL, loc);
- mpz_clear(val);
- bytes->push_back(byte);
- }
-
- Expression* e = Expression::make_composite_literal(array_type, 0, false,
- bytes, loc);
-
- Variable* var = new Variable(array_type, e, true, false, false, loc);
-
- static int count;
- char buf[50];
- snprintf(buf, sizeof buf, "fieldtrack.%d", count);
- ++count;
-
- Named_object* no = gogo->add_variable(buf, var);
- e = Expression::make_var_reference(no, loc);
- e = Expression::make_unary(OPERATOR_AND, e, loc);
-
- Expression* call = Runtime::make_call(Runtime::FIELDTRACK, loc, 1, e);
- inserter->insert(Statement::make_statement(call, false));
-
- // Put this function, and the global variable we just created, into
- // unique sections. This will permit the linker to garbage collect
- // them if they are not referenced. The effect is that the only
- // strings, indicating field references, that will wind up in the
- // executable will be those for functions that are actually needed.
- if (function != NULL)
- function->func_value()->set_in_unique_section();
- var->set_in_unique_section();
-
- return this;
-}
-
-// Return the type of a field reference.
-
-Type*
-Field_reference_expression::do_type()
-{
- Type* type = this->expr_->type();
- if (type->is_error())
- return type;
- Struct_type* struct_type = type->struct_type();
- go_assert(struct_type != NULL);
- return struct_type->field(this->field_index_)->type();
-}
-
-// Check the types for a field reference.
-
-void
-Field_reference_expression::do_check_types(Gogo*)
-{
- Type* type = this->expr_->type();
- if (type->is_error())
- return;
- Struct_type* struct_type = type->struct_type();
- go_assert(struct_type != NULL);
- go_assert(struct_type->field(this->field_index_) != NULL);
-}
-
-// Get a tree for a field reference.
-
-tree
-Field_reference_expression::do_get_tree(Translate_context* context)
-{
- tree struct_tree = this->expr_->get_tree(context);
- if (struct_tree == error_mark_node
- || TREE_TYPE(struct_tree) == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(TREE_TYPE(struct_tree)) == RECORD_TYPE);
- tree field = TYPE_FIELDS(TREE_TYPE(struct_tree));
- if (field == NULL_TREE)
- {
- // This can happen for a type which refers to itself indirectly
- // and then turns out to be erroneous.
- go_assert(saw_errors());
- return error_mark_node;
- }
- for (unsigned int i = this->field_index_; i > 0; --i)
- {
- field = DECL_CHAIN(field);
- go_assert(field != NULL_TREE);
- }
- if (TREE_TYPE(field) == error_mark_node)
- return error_mark_node;
- return build3(COMPONENT_REF, TREE_TYPE(field), struct_tree, field,
- NULL_TREE);
-}
-
-// Dump ast representation for a field reference expression.
-
-void
-Field_reference_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- this->expr_->dump_expression(ast_dump_context);
- ast_dump_context->ostream() << "." << this->field_index_;
-}
-
-// Make a reference to a qualified identifier in an expression.
-
-Field_reference_expression*
-Expression::make_field_reference(Expression* expr, unsigned int field_index,
- Location location)
-{
- return new Field_reference_expression(expr, field_index, location);
-}
-
-// Class Interface_field_reference_expression.
-
-// Return a tree for the pointer to the function to call.
-
-tree
-Interface_field_reference_expression::get_function_tree(Translate_context*,
- tree expr)
-{
- if (this->expr_->type()->points_to() != NULL)
- expr = build_fold_indirect_ref(expr);
-
- tree expr_type = TREE_TYPE(expr);
- go_assert(TREE_CODE(expr_type) == RECORD_TYPE);
-
- tree field = TYPE_FIELDS(expr_type);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0);
-
- tree table = build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
- go_assert(POINTER_TYPE_P(TREE_TYPE(table)));
-
- table = build_fold_indirect_ref(table);
- go_assert(TREE_CODE(TREE_TYPE(table)) == RECORD_TYPE);
-
- std::string name = Gogo::unpack_hidden_name(this->name_);
- for (field = DECL_CHAIN(TYPE_FIELDS(TREE_TYPE(table)));
- field != NULL_TREE;
- field = DECL_CHAIN(field))
- {
- if (name == IDENTIFIER_POINTER(DECL_NAME(field)))
- break;
- }
- go_assert(field != NULL_TREE);
-
- return build3(COMPONENT_REF, TREE_TYPE(field), table, field, NULL_TREE);
-}
-
-// Return a tree for the first argument to pass to the interface
-// function.
-
-tree
-Interface_field_reference_expression::get_underlying_object_tree(
- Translate_context*,
- tree expr)
-{
- if (this->expr_->type()->points_to() != NULL)
- expr = build_fold_indirect_ref(expr);
-
- tree expr_type = TREE_TYPE(expr);
- go_assert(TREE_CODE(expr_type) == RECORD_TYPE);
-
- tree field = DECL_CHAIN(TYPE_FIELDS(expr_type));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
-
- return build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
-}
-
-// Traversal.
-
-int
-Interface_field_reference_expression::do_traverse(Traverse* traverse)
-{
- return Expression::traverse(&this->expr_, traverse);
-}
-
-// Return the type of an interface field reference.
-
-Type*
-Interface_field_reference_expression::do_type()
-{
- Type* expr_type = this->expr_->type();
-
- Type* points_to = expr_type->points_to();
- if (points_to != NULL)
- expr_type = points_to;
-
- Interface_type* interface_type = expr_type->interface_type();
- if (interface_type == NULL)
- return Type::make_error_type();
-
- const Typed_identifier* method = interface_type->find_method(this->name_);
- if (method == NULL)
- return Type::make_error_type();
-
- return method->type();
-}
-
-// Determine types.
-
-void
-Interface_field_reference_expression::do_determine_type(const Type_context*)
-{
- this->expr_->determine_type_no_context();
-}
-
-// Check the types for an interface field reference.
-
-void
-Interface_field_reference_expression::do_check_types(Gogo*)
-{
- Type* type = this->expr_->type();
-
- Type* points_to = type->points_to();
- if (points_to != NULL)
- type = points_to;
-
- Interface_type* interface_type = type->interface_type();
- if (interface_type == NULL)
- {
- if (!type->is_error_type())
- this->report_error(_("expected interface or pointer to interface"));
- }
- else
- {
- const Typed_identifier* method =
- interface_type->find_method(this->name_);
- if (method == NULL)
- {
- error_at(this->location(), "method %qs not in interface",
- Gogo::message_name(this->name_).c_str());
- this->set_is_error();
- }
- }
-}
-
-// Get a tree for a reference to a field in an interface. There is no
-// standard tree type representation for this: it's a function
-// attached to its first argument, like a Bound_method_expression.
-// The only places it may currently be used are in a Call_expression
-// or a Go_statement, which will take it apart directly. So this has
-// nothing to do at present.
-
-tree
-Interface_field_reference_expression::do_get_tree(Translate_context*)
-{
- error_at(this->location(), "reference to method other than calling it");
- return error_mark_node;
-}
-
-// Dump ast representation for an interface field reference.
-
-void
-Interface_field_reference_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- this->expr_->dump_expression(ast_dump_context);
- ast_dump_context->ostream() << "." << this->name_;
-}
-
-// Make a reference to a field in an interface.
-
-Expression*
-Expression::make_interface_field_reference(Expression* expr,
- const std::string& field,
- Location location)
-{
- return new Interface_field_reference_expression(expr, field, location);
-}
-
-// A general selector. This is a Parser_expression for LEFT.NAME. It
-// is lowered after we know the type of the left hand side.
-
-class Selector_expression : public Parser_expression
-{
- public:
- Selector_expression(Expression* left, const std::string& name,
- Location location)
- : Parser_expression(EXPRESSION_SELECTOR, location),
- left_(left), name_(name)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Expression::traverse(&this->left_, traverse); }
-
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- Expression*
- do_copy()
- {
- return new Selector_expression(this->left_->copy(), this->name_,
- this->location());
- }
-
- void
- do_dump_expression(Ast_dump_context* ast_dump_context) const;
-
- private:
- Expression*
- lower_method_expression(Gogo*);
-
- // The expression on the left hand side.
- Expression* left_;
- // The name on the right hand side.
- std::string name_;
-};
-
-// Lower a selector expression once we know the real type of the left
-// hand side.
-
-Expression*
-Selector_expression::do_lower(Gogo* gogo, Named_object*, Statement_inserter*,
- int)
-{
- Expression* left = this->left_;
- if (left->is_type_expression())
- return this->lower_method_expression(gogo);
- return Type::bind_field_or_method(gogo, left->type(), left, this->name_,
- this->location());
-}
-
-// Lower a method expression T.M or (*T).M. We turn this into a
-// function literal.
-
-Expression*
-Selector_expression::lower_method_expression(Gogo* gogo)
-{
- Location location = this->location();
- Type* type = this->left_->type();
- const std::string& name(this->name_);
-
- bool is_pointer;
- if (type->points_to() == NULL)
- is_pointer = false;
- else
- {
- is_pointer = true;
- type = type->points_to();
- }
- Named_type* nt = type->named_type();
- if (nt == NULL)
- {
- error_at(location,
- ("method expression requires named type or "
- "pointer to named type"));
- return Expression::make_error(location);
- }
-
- bool is_ambiguous;
- Method* method = nt->method_function(name, &is_ambiguous);
- const Typed_identifier* imethod = NULL;
- if (method == NULL && !is_pointer)
- {
- Interface_type* it = nt->interface_type();
- if (it != NULL)
- imethod = it->find_method(name);
- }
-
- if (method == NULL && imethod == NULL)
- {
- if (!is_ambiguous)
- error_at(location, "type %<%s%s%> has no method %<%s%>",
- is_pointer ? "*" : "",
- nt->message_name().c_str(),
- Gogo::message_name(name).c_str());
- else
- error_at(location, "method %<%s%s%> is ambiguous in type %<%s%>",
- Gogo::message_name(name).c_str(),
- is_pointer ? "*" : "",
- nt->message_name().c_str());
- return Expression::make_error(location);
- }
-
- if (method != NULL && !is_pointer && !method->is_value_method())
- {
- error_at(location, "method requires pointer (use %<(*%s).%s)%>",
- nt->message_name().c_str(),
- Gogo::message_name(name).c_str());
- return Expression::make_error(location);
- }
-
- // Build a new function type in which the receiver becomes the first
- // argument.
- Function_type* method_type;
- if (method != NULL)
- {
- method_type = method->type();
- go_assert(method_type->is_method());
- }
- else
- {
- method_type = imethod->type()->function_type();
- go_assert(method_type != NULL && !method_type->is_method());
- }
-
- const char* const receiver_name = "$this";
- Typed_identifier_list* parameters = new Typed_identifier_list();
- parameters->push_back(Typed_identifier(receiver_name, this->left_->type(),
- location));
-
- const Typed_identifier_list* method_parameters = method_type->parameters();
- if (method_parameters != NULL)
- {
- int i = 0;
- for (Typed_identifier_list::const_iterator p = method_parameters->begin();
- p != method_parameters->end();
- ++p, ++i)
- {
- if (!p->name().empty())
- parameters->push_back(*p);
- else
- {
- char buf[20];
- snprintf(buf, sizeof buf, "$param%d", i);
- parameters->push_back(Typed_identifier(buf, p->type(),
- p->location()));
- }
- }
- }
-
- const Typed_identifier_list* method_results = method_type->results();
- Typed_identifier_list* results;
- if (method_results == NULL)
- results = NULL;
- else
- {
- results = new Typed_identifier_list();
- for (Typed_identifier_list::const_iterator p = method_results->begin();
- p != method_results->end();
- ++p)
- results->push_back(*p);
- }
-
- Function_type* fntype = Type::make_function_type(NULL, parameters, results,
- location);
- if (method_type->is_varargs())
- fntype->set_is_varargs();
-
- // We generate methods which always takes a pointer to the receiver
- // as their first argument. If this is for a pointer type, we can
- // simply reuse the existing function. We use an internal hack to
- // get the right type.
-
- if (method != NULL && is_pointer)
- {
- Named_object* mno = (method->needs_stub_method()
- ? method->stub_object()
- : method->named_object());
- Expression* f = Expression::make_func_reference(mno, NULL, location);
- f = Expression::make_cast(fntype, f, location);
- Type_conversion_expression* tce =
- static_cast<Type_conversion_expression*>(f);
- tce->set_may_convert_function_types();
- return f;
- }
-
- Named_object* no = gogo->start_function(Gogo::thunk_name(), fntype, false,
- location);
-
- Named_object* vno = gogo->lookup(receiver_name, NULL);
- go_assert(vno != NULL);
- Expression* ve = Expression::make_var_reference(vno, location);
- Expression* bm;
- if (method != NULL)
- bm = Type::bind_field_or_method(gogo, nt, ve, name, location);
- else
- bm = Expression::make_interface_field_reference(ve, name, location);
-
- // Even though we found the method above, if it has an error type we
- // may see an error here.
- if (bm->is_error_expression())
- {
- gogo->finish_function(location);
- return bm;
- }
-
- Expression_list* args;
- if (parameters->size() <= 1)
- args = NULL;
- else
- {
- args = new Expression_list();
- Typed_identifier_list::const_iterator p = parameters->begin();
- ++p;
- for (; p != parameters->end(); ++p)
- {
- vno = gogo->lookup(p->name(), NULL);
- go_assert(vno != NULL);
- args->push_back(Expression::make_var_reference(vno, location));
- }
- }
-
- gogo->start_block(location);
-
- Call_expression* call = Expression::make_call(bm, args,
- method_type->is_varargs(),
- location);
-
- size_t count = call->result_count();
- Statement* s;
- if (count == 0)
- s = Statement::make_statement(call, true);
- else
- {
- Expression_list* retvals = new Expression_list();
- if (count <= 1)
- retvals->push_back(call);
- else
- {
- for (size_t i = 0; i < count; ++i)
- retvals->push_back(Expression::make_call_result(call, i));
- }
- s = Statement::make_return_statement(retvals, location);
- }
- gogo->add_statement(s);
-
- Block* b = gogo->finish_block(location);
-
- gogo->add_block(b, location);
-
- // Lower the call in case there are multiple results.
- gogo->lower_block(no, b);
-
- gogo->finish_function(location);
-
- return Expression::make_func_reference(no, NULL, location);
-}
-
-// Dump the ast for a selector expression.
-
-void
-Selector_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
- const
-{
- ast_dump_context->dump_expression(this->left_);
- ast_dump_context->ostream() << ".";
- ast_dump_context->ostream() << this->name_;
-}
-
-// Make a selector expression.
-
-Expression*
-Expression::make_selector(Expression* left, const std::string& name,
- Location location)
-{
- return new Selector_expression(left, name, location);
-}
-
-// Implement the builtin function new.
-
-class Allocation_expression : public Expression
-{
- public:
- Allocation_expression(Type* type, Location location)
- : Expression(EXPRESSION_ALLOCATION, location),
- type_(type)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Type::traverse(this->type_, traverse); }
-
- Type*
- do_type()
- { return Type::make_pointer_type(this->type_); }
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- { return new Allocation_expression(this->type_, this->location()); }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type we are allocating.
- Type* type_;
-};
-
-// Return a tree for an allocation expression.
-
-tree
-Allocation_expression::do_get_tree(Translate_context* context)
-{
- tree type_tree = type_to_tree(this->type_->get_backend(context->gogo()));
- if (type_tree == error_mark_node)
- return error_mark_node;
- tree size_tree = TYPE_SIZE_UNIT(type_tree);
- tree space = context->gogo()->allocate_memory(this->type_, size_tree,
- this->location());
- if (space == error_mark_node)
- return error_mark_node;
- return fold_convert(build_pointer_type(type_tree), space);
-}
-
-// Dump ast representation for an allocation expression.
-
-void
-Allocation_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
- const
-{
- ast_dump_context->ostream() << "new(";
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << ")";
-}
-
-// Make an allocation expression.
-
-Expression*
-Expression::make_allocation(Type* type, Location location)
-{
- return new Allocation_expression(type, location);
-}
-
-// Construct a struct.
-
-class Struct_construction_expression : public Expression
-{
- public:
- Struct_construction_expression(Type* type, Expression_list* vals,
- Location location)
- : Expression(EXPRESSION_STRUCT_CONSTRUCTION, location),
- type_(type), vals_(vals), traverse_order_(NULL)
- { }
-
- // Set the traversal order, used to ensure that we implement the
- // order of evaluation rules. Takes ownership of the argument.
- void
- set_traverse_order(std::vector<int>* traverse_order)
- { this->traverse_order_ = traverse_order; }
-
- // Return whether this is a constant initializer.
- bool
- is_constant_struct() const;
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- Type*
- do_type()
- { return this->type_; }
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- Struct_construction_expression* ret =
- new Struct_construction_expression(this->type_, this->vals_->copy(),
- this->location());
- if (this->traverse_order_ != NULL)
- ret->set_traverse_order(this->traverse_order_);
- return ret;
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_export(Export*) const;
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type of the struct to construct.
- Type* type_;
- // The list of values, in order of the fields in the struct. A NULL
- // entry means that the field should be zero-initialized.
- Expression_list* vals_;
- // If not NULL, the order in which to traverse vals_. This is used
- // so that we implement the order of evaluation rules correctly.
- std::vector<int>* traverse_order_;
-};
-
-// Traversal.
-
-int
-Struct_construction_expression::do_traverse(Traverse* traverse)
-{
- if (this->vals_ != NULL)
- {
- if (this->traverse_order_ == NULL)
- {
- if (this->vals_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- else
- {
- for (std::vector<int>::const_iterator p =
- this->traverse_order_->begin();
- p != this->traverse_order_->end();
- ++p)
- {
- if (Expression::traverse(&this->vals_->at(*p), traverse)
- == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- }
- if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Return whether this is a constant initializer.
-
-bool
-Struct_construction_expression::is_constant_struct() const
-{
- if (this->vals_ == NULL)
- return true;
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv)
- {
- if (*pv != NULL
- && !(*pv)->is_constant()
- && (!(*pv)->is_composite_literal()
- || (*pv)->is_nonconstant_composite_literal()))
- return false;
- }
-
- const Struct_field_list* fields = this->type_->struct_type()->fields();
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf)
- {
- // There are no constant constructors for interfaces.
- if (pf->type()->interface_type() != NULL)
- return false;
- }
-
- return true;
-}
-
-// Final type determination.
-
-void
-Struct_construction_expression::do_determine_type(const Type_context*)
-{
- if (this->vals_ == NULL)
- return;
- const Struct_field_list* fields = this->type_->struct_type()->fields();
- Expression_list::const_iterator pv = this->vals_->begin();
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf, ++pv)
- {
- if (pv == this->vals_->end())
- return;
- if (*pv != NULL)
- {
- Type_context subcontext(pf->type(), false);
- (*pv)->determine_type(&subcontext);
- }
- }
- // Extra values are an error we will report elsewhere; we still want
- // to determine the type to avoid knockon errors.
- for (; pv != this->vals_->end(); ++pv)
- (*pv)->determine_type_no_context();
-}
-
-// Check types.
-
-void
-Struct_construction_expression::do_check_types(Gogo*)
-{
- if (this->vals_ == NULL)
- return;
-
- Struct_type* st = this->type_->struct_type();
- if (this->vals_->size() > st->field_count())
- {
- this->report_error(_("too many expressions for struct"));
- return;
- }
-
- const Struct_field_list* fields = st->fields();
- Expression_list::const_iterator pv = this->vals_->begin();
- int i = 0;
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf, ++pv, ++i)
- {
- if (pv == this->vals_->end())
- {
- this->report_error(_("too few expressions for struct"));
- break;
- }
-
- if (*pv == NULL)
- continue;
-
- std::string reason;
- if (!Type::are_assignable(pf->type(), (*pv)->type(), &reason))
- {
- if (reason.empty())
- error_at((*pv)->location(),
- "incompatible type for field %d in struct construction",
- i + 1);
- else
- error_at((*pv)->location(),
- ("incompatible type for field %d in "
- "struct construction (%s)"),
- i + 1, reason.c_str());
- this->set_is_error();
- }
- }
- go_assert(pv == this->vals_->end());
-}
-
-// Return a tree for constructing a struct.
-
-tree
-Struct_construction_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
-
- if (this->vals_ == NULL)
- {
- Btype* btype = this->type_->get_backend(gogo);
- return expr_to_tree(gogo->backend()->zero_expression(btype));
- }
-
- tree type_tree = type_to_tree(this->type_->get_backend(gogo));
- if (type_tree == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(type_tree) == RECORD_TYPE);
-
- bool is_constant = true;
- const Struct_field_list* fields = this->type_->struct_type()->fields();
- vec<constructor_elt, va_gc> *elts;
- vec_alloc (elts, fields->size());
- Struct_field_list::const_iterator pf = fields->begin();
- Expression_list::const_iterator pv = this->vals_->begin();
- for (tree field = TYPE_FIELDS(type_tree);
- field != NULL_TREE;
- field = DECL_CHAIN(field), ++pf)
- {
- go_assert(pf != fields->end());
-
- Btype* fbtype = pf->type()->get_backend(gogo);
-
- tree val;
- if (pv == this->vals_->end())
- val = expr_to_tree(gogo->backend()->zero_expression(fbtype));
- else if (*pv == NULL)
- {
- val = expr_to_tree(gogo->backend()->zero_expression(fbtype));
- ++pv;
- }
- else
- {
- val = Expression::convert_for_assignment(context, pf->type(),
- (*pv)->type(),
- (*pv)->get_tree(context),
- this->location());
- ++pv;
- }
-
- if (val == error_mark_node || TREE_TYPE(val) == error_mark_node)
- return error_mark_node;
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = elts->quick_push(empty);
- elt->index = field;
- elt->value = val;
- if (!TREE_CONSTANT(val))
- is_constant = false;
- }
- go_assert(pf == fields->end());
-
- tree ret = build_constructor(type_tree, elts);
- if (is_constant)
- TREE_CONSTANT(ret) = 1;
- return ret;
-}
-
-// Export a struct construction.
-
-void
-Struct_construction_expression::do_export(Export* exp) const
-{
- exp->write_c_string("convert(");
- exp->write_type(this->type_);
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv)
- {
- exp->write_c_string(", ");
- if (*pv != NULL)
- (*pv)->export_expression(exp);
- }
- exp->write_c_string(")");
-}
-
-// Dump ast representation of a struct construction expression.
-
-void
-Struct_construction_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << "{";
- ast_dump_context->dump_expression_list(this->vals_);
- ast_dump_context->ostream() << "}";
-}
-
-// Make a struct composite literal. This used by the thunk code.
-
-Expression*
-Expression::make_struct_composite_literal(Type* type, Expression_list* vals,
- Location location)
-{
- go_assert(type->struct_type() != NULL);
- return new Struct_construction_expression(type, vals, location);
-}
-
-// Construct an array. This class is not used directly; instead we
-// use the child classes, Fixed_array_construction_expression and
-// Open_array_construction_expression.
-
-class Array_construction_expression : public Expression
-{
- protected:
- Array_construction_expression(Expression_classification classification,
- Type* type,
- const std::vector<unsigned long>* indexes,
- Expression_list* vals, Location location)
- : Expression(classification, location),
- type_(type), indexes_(indexes), vals_(vals)
- { go_assert(indexes == NULL || indexes->size() == vals->size()); }
-
- public:
- // Return whether this is a constant initializer.
- bool
- is_constant_array() const;
-
- // Return the number of elements.
- size_t
- element_count() const
- { return this->vals_ == NULL ? 0 : this->vals_->size(); }
-
-protected:
- int
- do_traverse(Traverse* traverse);
-
- Type*
- do_type()
- { return this->type_; }
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- void
- do_export(Export*) const;
-
- // The indexes.
- const std::vector<unsigned long>*
- indexes()
- { return this->indexes_; }
-
- // The list of values.
- Expression_list*
- vals()
- { return this->vals_; }
-
- // Get a constructor tree for the array values.
- tree
- get_constructor_tree(Translate_context* context, tree type_tree);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type of the array to construct.
- Type* type_;
- // The list of indexes into the array, one for each value. This may
- // be NULL, in which case the indexes start at zero and increment.
- const std::vector<unsigned long>* indexes_;
- // The list of values. This may be NULL if there are no values.
- Expression_list* vals_;
-};
-
-// Traversal.
-
-int
-Array_construction_expression::do_traverse(Traverse* traverse)
-{
- if (this->vals_ != NULL
- && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Return whether this is a constant initializer.
-
-bool
-Array_construction_expression::is_constant_array() const
-{
- if (this->vals_ == NULL)
- return true;
-
- // There are no constant constructors for interfaces.
- if (this->type_->array_type()->element_type()->interface_type() != NULL)
- return false;
-
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv)
- {
- if (*pv != NULL
- && !(*pv)->is_constant()
- && (!(*pv)->is_composite_literal()
- || (*pv)->is_nonconstant_composite_literal()))
- return false;
- }
- return true;
-}
-
-// Final type determination.
-
-void
-Array_construction_expression::do_determine_type(const Type_context*)
-{
- if (this->vals_ == NULL)
- return;
- Type_context subcontext(this->type_->array_type()->element_type(), false);
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv)
- {
- if (*pv != NULL)
- (*pv)->determine_type(&subcontext);
- }
-}
-
-// Check types.
-
-void
-Array_construction_expression::do_check_types(Gogo*)
-{
- if (this->vals_ == NULL)
- return;
-
- Array_type* at = this->type_->array_type();
- int i = 0;
- Type* element_type = at->element_type();
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv, ++i)
- {
- if (*pv != NULL
- && !Type::are_assignable(element_type, (*pv)->type(), NULL))
- {
- error_at((*pv)->location(),
- "incompatible type for element %d in composite literal",
- i + 1);
- this->set_is_error();
- }
- }
-}
-
-// Get a constructor tree for the array values.
-
-tree
-Array_construction_expression::get_constructor_tree(Translate_context* context,
- tree type_tree)
-{
- vec<constructor_elt, va_gc> *values;
- vec_alloc (values, (this->vals_ == NULL ? 0 : this->vals_->size()));
- Type* element_type = this->type_->array_type()->element_type();
- bool is_constant = true;
- if (this->vals_ != NULL)
- {
- size_t i = 0;
- std::vector<unsigned long>::const_iterator pi;
- if (this->indexes_ != NULL)
- pi = this->indexes_->begin();
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv, ++i)
- {
- if (this->indexes_ != NULL)
- go_assert(pi != this->indexes_->end());
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = values->quick_push(empty);
-
- if (this->indexes_ == NULL)
- elt->index = size_int(i);
- else
- elt->index = size_int(*pi);
-
- if (*pv == NULL)
- {
- Gogo* gogo = context->gogo();
- Btype* ebtype = element_type->get_backend(gogo);
- Bexpression *zv = gogo->backend()->zero_expression(ebtype);
- elt->value = expr_to_tree(zv);
- }
- else
- {
- tree value_tree = (*pv)->get_tree(context);
- elt->value = Expression::convert_for_assignment(context,
- element_type,
- (*pv)->type(),
- value_tree,
- this->location());
- }
- if (elt->value == error_mark_node)
- return error_mark_node;
- if (!TREE_CONSTANT(elt->value))
- is_constant = false;
- if (this->indexes_ != NULL)
- ++pi;
- }
- if (this->indexes_ != NULL)
- go_assert(pi == this->indexes_->end());
- }
-
- tree ret = build_constructor(type_tree, values);
- if (is_constant)
- TREE_CONSTANT(ret) = 1;
- return ret;
-}
-
-// Export an array construction.
-
-void
-Array_construction_expression::do_export(Export* exp) const
-{
- exp->write_c_string("convert(");
- exp->write_type(this->type_);
- if (this->vals_ != NULL)
- {
- std::vector<unsigned long>::const_iterator pi;
- if (this->indexes_ != NULL)
- pi = this->indexes_->begin();
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv)
- {
- exp->write_c_string(", ");
-
- if (this->indexes_ != NULL)
- {
- char buf[100];
- snprintf(buf, sizeof buf, "%lu", *pi);
- exp->write_c_string(buf);
- exp->write_c_string(":");
- }
-
- if (*pv != NULL)
- (*pv)->export_expression(exp);
-
- if (this->indexes_ != NULL)
- ++pi;
- }
- }
- exp->write_c_string(")");
-}
-
-// Dump ast representation of an array construction expressin.
-
-void
-Array_construction_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- Expression* length = this->type_->array_type()->length();
-
- ast_dump_context->ostream() << "[" ;
- if (length != NULL)
- {
- ast_dump_context->dump_expression(length);
- }
- ast_dump_context->ostream() << "]" ;
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << "{" ;
- if (this->indexes_ == NULL)
- ast_dump_context->dump_expression_list(this->vals_);
- else
- {
- Expression_list::const_iterator pv = this->vals_->begin();
- for (std::vector<unsigned long>::const_iterator pi =
- this->indexes_->begin();
- pi != this->indexes_->end();
- ++pi, ++pv)
- {
- if (pi != this->indexes_->begin())
- ast_dump_context->ostream() << ", ";
- ast_dump_context->ostream() << *pi << ':';
- ast_dump_context->dump_expression(*pv);
- }
- }
- ast_dump_context->ostream() << "}" ;
-
-}
-
-// Construct a fixed array.
-
-class Fixed_array_construction_expression :
- public Array_construction_expression
-{
- public:
- Fixed_array_construction_expression(Type* type,
- const std::vector<unsigned long>* indexes,
- Expression_list* vals, Location location)
- : Array_construction_expression(EXPRESSION_FIXED_ARRAY_CONSTRUCTION,
- type, indexes, vals, location)
- { go_assert(type->array_type() != NULL && !type->is_slice_type()); }
-
- protected:
- Expression*
- do_copy()
- {
- return new Fixed_array_construction_expression(this->type(),
- this->indexes(),
- (this->vals() == NULL
- ? NULL
- : this->vals()->copy()),
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-};
-
-// Return a tree for constructing a fixed array.
-
-tree
-Fixed_array_construction_expression::do_get_tree(Translate_context* context)
-{
- Type* type = this->type();
- Btype* btype = type->get_backend(context->gogo());
- return this->get_constructor_tree(context, type_to_tree(btype));
-}
-
-// Construct an open array.
-
-class Open_array_construction_expression : public Array_construction_expression
-{
- public:
- Open_array_construction_expression(Type* type,
- const std::vector<unsigned long>* indexes,
- Expression_list* vals, Location location)
- : Array_construction_expression(EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
- type, indexes, vals, location)
- { go_assert(type->is_slice_type()); }
-
- protected:
- // Note that taking the address of an open array literal is invalid.
-
- Expression*
- do_copy()
- {
- return new Open_array_construction_expression(this->type(),
- this->indexes(),
- (this->vals() == NULL
- ? NULL
- : this->vals()->copy()),
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-};
-
-// Return a tree for constructing an open array.
-
-tree
-Open_array_construction_expression::do_get_tree(Translate_context* context)
-{
- Array_type* array_type = this->type()->array_type();
- if (array_type == NULL)
- {
- go_assert(this->type()->is_error());
- return error_mark_node;
- }
-
- Type* element_type = array_type->element_type();
- Btype* belement_type = element_type->get_backend(context->gogo());
- tree element_type_tree = type_to_tree(belement_type);
- if (element_type_tree == error_mark_node)
- return error_mark_node;
-
- tree values;
- tree length_tree;
- if (this->vals() == NULL || this->vals()->empty())
- {
- // We need to create a unique value.
- tree max = size_int(0);
- tree constructor_type = build_array_type(element_type_tree,
- build_index_type(max));
- if (constructor_type == error_mark_node)
- return error_mark_node;
- vec<constructor_elt, va_gc> *vec;
- vec_alloc(vec, 1);
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = vec->quick_push(empty);
- elt->index = size_int(0);
- Gogo* gogo = context->gogo();
- Btype* btype = element_type->get_backend(gogo);
- elt->value = expr_to_tree(gogo->backend()->zero_expression(btype));
- values = build_constructor(constructor_type, vec);
- if (TREE_CONSTANT(elt->value))
- TREE_CONSTANT(values) = 1;
- length_tree = size_int(0);
- }
- else
- {
- unsigned long max_index;
- if (this->indexes() == NULL)
- max_index = this->vals()->size() - 1;
- else
- max_index = this->indexes()->back();
- tree max_tree = size_int(max_index);
- tree constructor_type = build_array_type(element_type_tree,
- build_index_type(max_tree));
- if (constructor_type == error_mark_node)
- return error_mark_node;
- values = this->get_constructor_tree(context, constructor_type);
- length_tree = size_int(max_index + 1);
- }
-
- if (values == error_mark_node)
- return error_mark_node;
-
- bool is_constant_initializer = TREE_CONSTANT(values);
-
- // We have to copy the initial values into heap memory if we are in
- // a function or if the values are not constants. We also have to
- // copy them if they may contain pointers in a non-constant context,
- // as otherwise the garbage collector won't see them.
- bool copy_to_heap = (context->function() != NULL
- || !is_constant_initializer
- || (element_type->has_pointer()
- && !context->is_const()));
-
- if (is_constant_initializer)
- {
- tree tmp = build_decl(this->location().gcc_location(), VAR_DECL,
- create_tmp_var_name("C"), TREE_TYPE(values));
- DECL_EXTERNAL(tmp) = 0;
- TREE_PUBLIC(tmp) = 0;
- TREE_STATIC(tmp) = 1;
- DECL_ARTIFICIAL(tmp) = 1;
- if (copy_to_heap)
- {
- // If we are not copying the value to the heap, we will only
- // initialize the value once, so we can use this directly
- // rather than copying it. In that case we can't make it
- // read-only, because the program is permitted to change it.
- TREE_READONLY(tmp) = 1;
- TREE_CONSTANT(tmp) = 1;
- }
- DECL_INITIAL(tmp) = values;
- rest_of_decl_compilation(tmp, 1, 0);
- values = tmp;
- }
-
- tree space;
- tree set;
- if (!copy_to_heap)
- {
- // the initializer will only run once.
- space = build_fold_addr_expr(values);
- set = NULL_TREE;
- }
- else
- {
- tree memsize = TYPE_SIZE_UNIT(TREE_TYPE(values));
- space = context->gogo()->allocate_memory(element_type, memsize,
- this->location());
- space = save_expr(space);
-
- tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space);
- tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
- s);
- TREE_THIS_NOTRAP(ref) = 1;
- set = build2(MODIFY_EXPR, void_type_node, ref, values);
- }
-
- // Build a constructor for the open array.
-
- tree type_tree = type_to_tree(this->type()->get_backend(context->gogo()));
- if (type_tree == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(type_tree) == RECORD_TYPE);
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 3);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(type_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), space);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), length_tree);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),"__capacity") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), length_tree);
-
- tree constructor = build_constructor(type_tree, init);
- if (constructor == error_mark_node)
- return error_mark_node;
- if (!copy_to_heap)
- TREE_CONSTANT(constructor) = 1;
-
- if (set == NULL_TREE)
- return constructor;
- else
- return build2(COMPOUND_EXPR, type_tree, set, constructor);
-}
-
-// Make a slice composite literal. This is used by the type
-// descriptor code.
-
-Expression*
-Expression::make_slice_composite_literal(Type* type, Expression_list* vals,
- Location location)
-{
- go_assert(type->is_slice_type());
- return new Open_array_construction_expression(type, NULL, vals, location);
-}
-
-// Construct a map.
-
-class Map_construction_expression : public Expression
-{
- public:
- Map_construction_expression(Type* type, Expression_list* vals,
- Location location)
- : Expression(EXPRESSION_MAP_CONSTRUCTION, location),
- type_(type), vals_(vals)
- { go_assert(vals == NULL || vals->size() % 2 == 0); }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- Type*
- do_type()
- { return this->type_; }
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return new Map_construction_expression(this->type_, this->vals_->copy(),
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_export(Export*) const;
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type of the map to construct.
- Type* type_;
- // The list of values.
- Expression_list* vals_;
-};
-
-// Traversal.
-
-int
-Map_construction_expression::do_traverse(Traverse* traverse)
-{
- if (this->vals_ != NULL
- && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Final type determination.
-
-void
-Map_construction_expression::do_determine_type(const Type_context*)
-{
- if (this->vals_ == NULL)
- return;
-
- Map_type* mt = this->type_->map_type();
- Type_context key_context(mt->key_type(), false);
- Type_context val_context(mt->val_type(), false);
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv)
- {
- (*pv)->determine_type(&key_context);
- ++pv;
- (*pv)->determine_type(&val_context);
- }
-}
-
-// Check types.
-
-void
-Map_construction_expression::do_check_types(Gogo*)
-{
- if (this->vals_ == NULL)
- return;
-
- Map_type* mt = this->type_->map_type();
- int i = 0;
- Type* key_type = mt->key_type();
- Type* val_type = mt->val_type();
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv, ++i)
- {
- if (!Type::are_assignable(key_type, (*pv)->type(), NULL))
- {
- error_at((*pv)->location(),
- "incompatible type for element %d key in map construction",
- i + 1);
- this->set_is_error();
- }
- ++pv;
- if (!Type::are_assignable(val_type, (*pv)->type(), NULL))
- {
- error_at((*pv)->location(),
- ("incompatible type for element %d value "
- "in map construction"),
- i + 1);
- this->set_is_error();
- }
- }
-}
-
-// Return a tree for constructing a map.
-
-tree
-Map_construction_expression::do_get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
- Location loc = this->location();
-
- Map_type* mt = this->type_->map_type();
-
- // Build a struct to hold the key and value.
- tree struct_type = make_node(RECORD_TYPE);
-
- Type* key_type = mt->key_type();
- tree id = get_identifier("__key");
- tree key_type_tree = type_to_tree(key_type->get_backend(gogo));
- if (key_type_tree == error_mark_node)
- return error_mark_node;
- tree key_field = build_decl(loc.gcc_location(), FIELD_DECL, id,
- key_type_tree);
- DECL_CONTEXT(key_field) = struct_type;
- TYPE_FIELDS(struct_type) = key_field;
-
- Type* val_type = mt->val_type();
- id = get_identifier("__val");
- tree val_type_tree = type_to_tree(val_type->get_backend(gogo));
- if (val_type_tree == error_mark_node)
- return error_mark_node;
- tree val_field = build_decl(loc.gcc_location(), FIELD_DECL, id,
- val_type_tree);
- DECL_CONTEXT(val_field) = struct_type;
- DECL_CHAIN(key_field) = val_field;
-
- layout_type(struct_type);
-
- bool is_constant = true;
- size_t i = 0;
- tree valaddr;
- tree make_tmp;
-
- if (this->vals_ == NULL || this->vals_->empty())
- {
- valaddr = null_pointer_node;
- make_tmp = NULL_TREE;
- }
- else
- {
- vec<constructor_elt, va_gc> *values;
- vec_alloc(values, this->vals_->size() / 2);
-
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv, ++i)
- {
- bool one_is_constant = true;
-
- vec<constructor_elt, va_gc> *one;
- vec_alloc(one, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = one->quick_push(empty);
- elt->index = key_field;
- tree val_tree = (*pv)->get_tree(context);
- elt->value = Expression::convert_for_assignment(context, key_type,
- (*pv)->type(),
- val_tree, loc);
- if (elt->value == error_mark_node)
- return error_mark_node;
- if (!TREE_CONSTANT(elt->value))
- one_is_constant = false;
-
- ++pv;
-
- elt = one->quick_push(empty);
- elt->index = val_field;
- val_tree = (*pv)->get_tree(context);
- elt->value = Expression::convert_for_assignment(context, val_type,
- (*pv)->type(),
- val_tree, loc);
- if (elt->value == error_mark_node)
- return error_mark_node;
- if (!TREE_CONSTANT(elt->value))
- one_is_constant = false;
-
- elt = values->quick_push(empty);
- elt->index = size_int(i);
- elt->value = build_constructor(struct_type, one);
- if (one_is_constant)
- TREE_CONSTANT(elt->value) = 1;
- else
- is_constant = false;
- }
-
- tree index_type = build_index_type(size_int(i - 1));
- tree array_type = build_array_type(struct_type, index_type);
- tree init = build_constructor(array_type, values);
- if (is_constant)
- TREE_CONSTANT(init) = 1;
- tree tmp;
- if (current_function_decl != NULL)
- {
- tmp = create_tmp_var(array_type, get_name(array_type));
- DECL_INITIAL(tmp) = init;
- make_tmp = fold_build1_loc(loc.gcc_location(), DECL_EXPR,
- void_type_node, tmp);
- TREE_ADDRESSABLE(tmp) = 1;
- }
- else
- {
- tmp = build_decl(loc.gcc_location(), VAR_DECL,
- create_tmp_var_name("M"), array_type);
- DECL_EXTERNAL(tmp) = 0;
- TREE_PUBLIC(tmp) = 0;
- TREE_STATIC(tmp) = 1;
- DECL_ARTIFICIAL(tmp) = 1;
- if (!TREE_CONSTANT(init))
- make_tmp = fold_build2_loc(loc.gcc_location(), INIT_EXPR,
- void_type_node, tmp, init);
- else
- {
- TREE_READONLY(tmp) = 1;
- TREE_CONSTANT(tmp) = 1;
- DECL_INITIAL(tmp) = init;
- make_tmp = NULL_TREE;
- }
- rest_of_decl_compilation(tmp, 1, 0);
- }
-
- valaddr = build_fold_addr_expr(tmp);
- }
-
- tree descriptor = mt->map_descriptor_pointer(gogo, loc);
-
- tree type_tree = type_to_tree(this->type_->get_backend(gogo));
- if (type_tree == error_mark_node)
- return error_mark_node;
-
- static tree construct_map_fndecl;
- tree call = Gogo::call_builtin(&construct_map_fndecl,
- loc,
- "__go_construct_map",
- 6,
- type_tree,
- TREE_TYPE(descriptor),
- descriptor,
- sizetype,
- size_int(i),
- sizetype,
- TYPE_SIZE_UNIT(struct_type),
- sizetype,
- byte_position(val_field),
- sizetype,
- 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)
- ret = call;
- else
- ret = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, type_tree,
- make_tmp, call);
- return ret;
-}
-
-// Export an array construction.
-
-void
-Map_construction_expression::do_export(Export* exp) const
-{
- exp->write_c_string("convert(");
- exp->write_type(this->type_);
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
- ++pv)
- {
- exp->write_c_string(", ");
- (*pv)->export_expression(exp);
- }
- exp->write_c_string(")");
-}
-
-// Dump ast representation for a map construction expression.
-
-void
-Map_construction_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << "{" ;
- ast_dump_context->dump_expression_list(this->vals_, true);
- ast_dump_context->ostream() << "}";
-}
-
-// A general composite literal. This is lowered to a type specific
-// version.
-
-class Composite_literal_expression : public Parser_expression
-{
- public:
- Composite_literal_expression(Type* type, int depth, bool has_keys,
- Expression_list* vals, Location location)
- : Parser_expression(EXPRESSION_COMPOSITE_LITERAL, location),
- type_(type), depth_(depth), vals_(vals), has_keys_(has_keys)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- Expression*
- do_copy()
- {
- return new Composite_literal_expression(this->type_, this->depth_,
- this->has_keys_,
- (this->vals_ == NULL
- ? NULL
- : this->vals_->copy()),
- this->location());
- }
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- Expression*
- lower_struct(Gogo*, Type*);
-
- Expression*
- lower_array(Type*);
-
- Expression*
- make_array(Type*, const std::vector<unsigned long>*, Expression_list*);
-
- Expression*
- lower_map(Gogo*, Named_object*, Statement_inserter*, Type*);
-
- // The type of the composite literal.
- Type* type_;
- // The depth within a list of composite literals within a composite
- // literal, when the type is omitted.
- int depth_;
- // The values to put in the composite literal.
- Expression_list* vals_;
- // If this is true, then VALS_ is a list of pairs: a key and a
- // value. In an array initializer, a missing key will be NULL.
- bool has_keys_;
-};
-
-// Traversal.
-
-int
-Composite_literal_expression::do_traverse(Traverse* traverse)
-{
- if (this->vals_ != NULL
- && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return Type::traverse(this->type_, traverse);
-}
-
-// Lower a generic composite literal into a specific version based on
-// the type.
-
-Expression*
-Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function,
- Statement_inserter* inserter, int)
-{
- Type* type = this->type_;
-
- for (int depth = this->depth_; depth > 0; --depth)
- {
- if (type->array_type() != NULL)
- type = type->array_type()->element_type();
- else if (type->map_type() != NULL)
- type = type->map_type()->val_type();
- else
- {
- if (!type->is_error())
- error_at(this->location(),
- ("may only omit types within composite literals "
- "of slice, array, or map type"));
- return Expression::make_error(this->location());
- }
- }
-
- Type *pt = type->points_to();
- bool is_pointer = false;
- if (pt != NULL)
- {
- is_pointer = true;
- type = pt;
- }
-
- Expression* ret;
- if (type->is_error())
- return Expression::make_error(this->location());
- else if (type->struct_type() != NULL)
- ret = this->lower_struct(gogo, type);
- else if (type->array_type() != NULL)
- ret = this->lower_array(type);
- else if (type->map_type() != NULL)
- ret = this->lower_map(gogo, function, inserter, type);
- else
- {
- error_at(this->location(),
- ("expected struct, slice, array, or map type "
- "for composite literal"));
- return Expression::make_error(this->location());
- }
-
- if (is_pointer)
- ret = Expression::make_heap_composite(ret, this->location());
-
- return ret;
-}
-
-// Lower a struct composite literal.
-
-Expression*
-Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
-{
- Location location = this->location();
- Struct_type* st = type->struct_type();
- if (this->vals_ == NULL || !this->has_keys_)
- {
- if (this->vals_ != NULL
- && !this->vals_->empty()
- && type->named_type() != NULL
- && type->named_type()->named_object()->package() != NULL)
- {
- for (Struct_field_list::const_iterator pf = st->fields()->begin();
- pf != st->fields()->end();
- ++pf)
- {
- if (Gogo::is_hidden_name(pf->field_name()))
- error_at(this->location(),
- "assignment of unexported field %qs in %qs literal",
- Gogo::message_name(pf->field_name()).c_str(),
- type->named_type()->message_name().c_str());
- }
- }
-
- return new Struct_construction_expression(type, this->vals_, location);
- }
-
- size_t field_count = st->field_count();
- std::vector<Expression*> vals(field_count);
- std::vector<int>* traverse_order = new(std::vector<int>);
- Expression_list::const_iterator p = this->vals_->begin();
- while (p != this->vals_->end())
- {
- Expression* name_expr = *p;
-
- ++p;
- go_assert(p != this->vals_->end());
- Expression* val = *p;
-
- ++p;
-
- if (name_expr == NULL)
- {
- error_at(val->location(), "mixture of field and value initializers");
- return Expression::make_error(location);
- }
-
- bool bad_key = false;
- std::string name;
- const Named_object* no = NULL;
- switch (name_expr->classification())
- {
- case EXPRESSION_UNKNOWN_REFERENCE:
- name = name_expr->unknown_expression()->name();
- break;
-
- case EXPRESSION_CONST_REFERENCE:
- no = static_cast<Const_expression*>(name_expr)->named_object();
- break;
-
- case EXPRESSION_TYPE:
- {
- Type* t = name_expr->type();
- Named_type* nt = t->named_type();
- if (nt == NULL)
- bad_key = true;
- else
- no = nt->named_object();
- }
- break;
-
- case EXPRESSION_VAR_REFERENCE:
- no = name_expr->var_expression()->named_object();
- break;
-
- case EXPRESSION_FUNC_REFERENCE:
- no = name_expr->func_expression()->named_object();
- break;
-
- case EXPRESSION_UNARY:
- // If there is a local variable around with the same name as
- // the field, and this occurs in the closure, then the
- // parser may turn the field reference into an indirection
- // through the closure. FIXME: This is a mess.
- {
- bad_key = true;
- Unary_expression* ue = static_cast<Unary_expression*>(name_expr);
- if (ue->op() == OPERATOR_MULT)
- {
- Field_reference_expression* fre =
- ue->operand()->field_reference_expression();
- if (fre != NULL)
- {
- Struct_type* st =
- fre->expr()->type()->deref()->struct_type();
- if (st != NULL)
- {
- const Struct_field* sf = st->field(fre->field_index());
- name = sf->field_name();
-
- // See below. FIXME.
- if (!Gogo::is_hidden_name(name)
- && name[0] >= 'a'
- && name[0] <= 'z')
- {
- if (gogo->lookup_global(name.c_str()) != NULL)
- name = gogo->pack_hidden_name(name, false);
- }
-
- char buf[20];
- snprintf(buf, sizeof buf, "%u", fre->field_index());
- size_t buflen = strlen(buf);
- if (name.compare(name.length() - buflen, buflen, buf)
- == 0)
- {
- name = name.substr(0, name.length() - buflen);
- bad_key = false;
- }
- }
- }
- }
- }
- break;
-
- default:
- bad_key = true;
- break;
- }
- if (bad_key)
- {
- error_at(name_expr->location(), "expected struct field name");
- return Expression::make_error(location);
- }
-
- if (no != NULL)
- {
- name = no->name();
-
- // A predefined name won't be packed. If it starts with a
- // lower case letter we need to check for that case, because
- // the field name will be packed. FIXME.
- if (!Gogo::is_hidden_name(name)
- && name[0] >= 'a'
- && name[0] <= 'z')
- {
- Named_object* gno = gogo->lookup_global(name.c_str());
- if (gno == no)
- name = gogo->pack_hidden_name(name, false);
- }
- }
-
- unsigned int index;
- const Struct_field* sf = st->find_local_field(name, &index);
- if (sf == NULL)
- {
- error_at(name_expr->location(), "unknown field %qs in %qs",
- Gogo::message_name(name).c_str(),
- (type->named_type() != NULL
- ? type->named_type()->message_name().c_str()
- : "unnamed struct"));
- return Expression::make_error(location);
- }
- if (vals[index] != NULL)
- {
- error_at(name_expr->location(),
- "duplicate value for field %qs in %qs",
- Gogo::message_name(name).c_str(),
- (type->named_type() != NULL
- ? type->named_type()->message_name().c_str()
- : "unnamed struct"));
- return Expression::make_error(location);
- }
-
- if (type->named_type() != NULL
- && type->named_type()->named_object()->package() != NULL
- && Gogo::is_hidden_name(sf->field_name()))
- error_at(name_expr->location(),
- "assignment of unexported field %qs in %qs literal",
- Gogo::message_name(sf->field_name()).c_str(),
- type->named_type()->message_name().c_str());
-
- vals[index] = val;
- traverse_order->push_back(index);
- }
-
- Expression_list* list = new Expression_list;
- list->reserve(field_count);
- for (size_t i = 0; i < field_count; ++i)
- list->push_back(vals[i]);
-
- Struct_construction_expression* ret =
- new Struct_construction_expression(type, list, location);
- ret->set_traverse_order(traverse_order);
- return ret;
-}
-
-// Used to sort an index/value array.
-
-class Index_value_compare
-{
- public:
- bool
- operator()(const std::pair<unsigned long, Expression*>& a,
- const std::pair<unsigned long, Expression*>& b)
- { return a.first < b.first; }
-};
-
-// Lower an array composite literal.
-
-Expression*
-Composite_literal_expression::lower_array(Type* type)
-{
- Location location = this->location();
- if (this->vals_ == NULL || !this->has_keys_)
- return this->make_array(type, NULL, this->vals_);
-
- std::vector<unsigned long>* indexes = new std::vector<unsigned long>;
- indexes->reserve(this->vals_->size());
- bool indexes_out_of_order = false;
- Expression_list* vals = new Expression_list();
- vals->reserve(this->vals_->size());
- unsigned long index = 0;
- Expression_list::const_iterator p = this->vals_->begin();
- while (p != this->vals_->end())
- {
- Expression* index_expr = *p;
-
- ++p;
- go_assert(p != this->vals_->end());
- Expression* val = *p;
-
- ++p;
-
- if (index_expr == NULL)
- {
- if (!indexes->empty())
- indexes->push_back(index);
- }
- else
- {
- if (indexes->empty() && !vals->empty())
- {
- for (size_t i = 0; i < vals->size(); ++i)
- indexes->push_back(i);
- }
-
- Numeric_constant nc;
- if (!index_expr->numeric_constant_value(&nc))
- {
- error_at(index_expr->location(),
- "index expression is not integer constant");
- return Expression::make_error(location);
- }
-
- switch (nc.to_unsigned_long(&index))
- {
- case Numeric_constant::NC_UL_VALID:
- break;
- case Numeric_constant::NC_UL_NOTINT:
- error_at(index_expr->location(),
- "index expression is not integer constant");
- return Expression::make_error(location);
- case Numeric_constant::NC_UL_NEGATIVE:
- error_at(index_expr->location(), "index expression is negative");
- return Expression::make_error(location);
- case Numeric_constant::NC_UL_BIG:
- error_at(index_expr->location(), "index value overflow");
- return Expression::make_error(location);
- default:
- go_unreachable();
- }
-
- Named_type* ntype = Type::lookup_integer_type("int");
- Integer_type* inttype = ntype->integer_type();
- if (sizeof(index) <= static_cast<size_t>(inttype->bits() * 8)
- && index >> (inttype->bits() - 1) != 0)
- {
- error_at(index_expr->location(), "index value overflow");
- return Expression::make_error(location);
- }
-
- if (std::find(indexes->begin(), indexes->end(), index)
- != indexes->end())
- {
- error_at(index_expr->location(), "duplicate value for index %lu",
- index);
- return Expression::make_error(location);
- }
-
- if (!indexes->empty() && index < indexes->back())
- indexes_out_of_order = true;
-
- indexes->push_back(index);
- }
-
- vals->push_back(val);
-
- ++index;
- }
-
- if (indexes->empty())
- {
- delete indexes;
- indexes = NULL;
- }
-
- if (indexes_out_of_order)
- {
- typedef std::vector<std::pair<unsigned long, Expression*> > V;
-
- V v;
- v.reserve(indexes->size());
- std::vector<unsigned long>::const_iterator pi = indexes->begin();
- for (Expression_list::const_iterator pe = vals->begin();
- pe != vals->end();
- ++pe, ++pi)
- v.push_back(std::make_pair(*pi, *pe));
-
- std::sort(v.begin(), v.end(), Index_value_compare());
-
- delete indexes;
- delete vals;
- indexes = new std::vector<unsigned long>();
- indexes->reserve(v.size());
- vals = new Expression_list();
- vals->reserve(v.size());
-
- for (V::const_iterator p = v.begin(); p != v.end(); ++p)
- {
- indexes->push_back(p->first);
- vals->push_back(p->second);
- }
- }
-
- return this->make_array(type, indexes, vals);
-}
-
-// Actually build the array composite literal. This handles
-// [...]{...}.
-
-Expression*
-Composite_literal_expression::make_array(
- Type* type,
- const std::vector<unsigned long>* indexes,
- Expression_list* vals)
-{
- Location location = this->location();
- Array_type* at = type->array_type();
-
- if (at->length() != NULL && at->length()->is_nil_expression())
- {
- size_t size;
- if (vals == NULL)
- size = 0;
- else if (indexes != NULL)
- size = indexes->back() + 1;
- else
- {
- size = vals->size();
- Integer_type* it = Type::lookup_integer_type("int")->integer_type();
- if (sizeof(size) <= static_cast<size_t>(it->bits() * 8)
- && size >> (it->bits() - 1) != 0)
- {
- error_at(location, "too many elements in composite literal");
- return Expression::make_error(location);
- }
- }
-
- mpz_t vlen;
- mpz_init_set_ui(vlen, size);
- Expression* elen = Expression::make_integer(&vlen, NULL, location);
- mpz_clear(vlen);
- at = Type::make_array_type(at->element_type(), elen);
- type = at;
- }
- else if (at->length() != NULL
- && !at->length()->is_error_expression()
- && this->vals_ != NULL)
- {
- Numeric_constant nc;
- unsigned long val;
- if (at->length()->numeric_constant_value(&nc)
- && nc.to_unsigned_long(&val) == Numeric_constant::NC_UL_VALID)
- {
- if (indexes == NULL)
- {
- if (this->vals_->size() > val)
- {
- error_at(location, "too many elements in composite literal");
- return Expression::make_error(location);
- }
- }
- else
- {
- unsigned long max = indexes->back();
- if (max >= val)
- {
- error_at(location,
- ("some element keys in composite literal "
- "are out of range"));
- return Expression::make_error(location);
- }
- }
- }
- }
-
- if (at->length() != NULL)
- return new Fixed_array_construction_expression(type, indexes, vals,
- location);
- else
- return new Open_array_construction_expression(type, indexes, vals,
- location);
-}
-
-// Lower a map composite literal.
-
-Expression*
-Composite_literal_expression::lower_map(Gogo* gogo, Named_object* function,
- Statement_inserter* inserter,
- Type* type)
-{
- Location location = this->location();
- if (this->vals_ != NULL)
- {
- if (!this->has_keys_)
- {
- error_at(location, "map composite literal must have keys");
- return Expression::make_error(location);
- }
-
- for (Expression_list::iterator p = this->vals_->begin();
- p != this->vals_->end();
- p += 2)
- {
- if (*p == NULL)
- {
- ++p;
- error_at((*p)->location(),
- "map composite literal must have keys for every value");
- return Expression::make_error(location);
- }
- // Make sure we have lowered the key; it may not have been
- // lowered in order to handle keys for struct composite
- // literals. Lower it now to get the right error message.
- if ((*p)->unknown_expression() != NULL)
- {
- (*p)->unknown_expression()->clear_is_composite_literal_key();
- gogo->lower_expression(function, inserter, &*p);
- go_assert((*p)->is_error_expression());
- return Expression::make_error(location);
- }
- }
- }
-
- return new Map_construction_expression(type, this->vals_, location);
-}
-
-// Dump ast representation for a composite literal expression.
-
-void
-Composite_literal_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << "composite(";
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << ", {";
- ast_dump_context->dump_expression_list(this->vals_, this->has_keys_);
- ast_dump_context->ostream() << "})";
-}
-
-// Make a composite literal expression.
-
-Expression*
-Expression::make_composite_literal(Type* type, int depth, bool has_keys,
- Expression_list* vals,
- Location location)
-{
- return new Composite_literal_expression(type, depth, has_keys, vals,
- location);
-}
-
-// Return whether this expression is a composite literal.
-
-bool
-Expression::is_composite_literal() const
-{
- switch (this->classification_)
- {
- case EXPRESSION_COMPOSITE_LITERAL:
- case EXPRESSION_STRUCT_CONSTRUCTION:
- case EXPRESSION_FIXED_ARRAY_CONSTRUCTION:
- case EXPRESSION_OPEN_ARRAY_CONSTRUCTION:
- case EXPRESSION_MAP_CONSTRUCTION:
- return true;
- default:
- return false;
- }
-}
-
-// Return whether this expression is a composite literal which is not
-// constant.
-
-bool
-Expression::is_nonconstant_composite_literal() const
-{
- switch (this->classification_)
- {
- case EXPRESSION_STRUCT_CONSTRUCTION:
- {
- const Struct_construction_expression *psce =
- static_cast<const Struct_construction_expression*>(this);
- return !psce->is_constant_struct();
- }
- case EXPRESSION_FIXED_ARRAY_CONSTRUCTION:
- {
- const Fixed_array_construction_expression *pace =
- static_cast<const Fixed_array_construction_expression*>(this);
- return !pace->is_constant_array();
- }
- case EXPRESSION_OPEN_ARRAY_CONSTRUCTION:
- {
- const Open_array_construction_expression *pace =
- static_cast<const Open_array_construction_expression*>(this);
- return !pace->is_constant_array();
- }
- case EXPRESSION_MAP_CONSTRUCTION:
- return true;
- default:
- return false;
- }
-}
-
-// Return true if this is a reference to a local variable.
-
-bool
-Expression::is_local_variable() const
-{
- const Var_expression* ve = this->var_expression();
- if (ve == NULL)
- return false;
- const Named_object* no = ve->named_object();
- return (no->is_result_variable()
- || (no->is_variable() && !no->var_value()->is_global()));
-}
-
-// Class Type_guard_expression.
-
-// Traversal.
-
-int
-Type_guard_expression::do_traverse(Traverse* traverse)
-{
- if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT
- || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Check types of a type guard expression. The expression must have
-// an interface type, but the actual type conversion is checked at run
-// time.
-
-void
-Type_guard_expression::do_check_types(Gogo*)
-{
- Type* expr_type = this->expr_->type();
- if (expr_type->interface_type() == NULL)
- {
- if (!expr_type->is_error() && !this->type_->is_error())
- this->report_error(_("type assertion only valid for interface types"));
- this->set_is_error();
- }
- else if (this->type_->interface_type() == NULL)
- {
- std::string reason;
- if (!expr_type->interface_type()->implements_interface(this->type_,
- &reason))
- {
- if (!this->type_->is_error())
- {
- if (reason.empty())
- this->report_error(_("impossible type assertion: "
- "type does not implement interface"));
- else
- error_at(this->location(),
- ("impossible type assertion: "
- "type does not implement interface (%s)"),
- reason.c_str());
- }
- this->set_is_error();
- }
- }
-}
-
-// Return a tree for a type guard expression.
-
-tree
-Type_guard_expression::do_get_tree(Translate_context* context)
-{
- tree expr_tree = this->expr_->get_tree(context);
- if (expr_tree == error_mark_node)
- return error_mark_node;
- if (this->type_->interface_type() != NULL)
- return Expression::convert_interface_to_interface(context, this->type_,
- this->expr_->type(),
- expr_tree, true,
- this->location());
- else
- return Expression::convert_for_assignment(context, this->type_,
- this->expr_->type(), expr_tree,
- this->location());
-}
-
-// Dump ast representation for a type guard expression.
-
-void
-Type_guard_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
- const
-{
- this->expr_->dump_expression(ast_dump_context);
- ast_dump_context->ostream() << ".";
- ast_dump_context->dump_type(this->type_);
-}
-
-// Make a type guard expression.
-
-Expression*
-Expression::make_type_guard(Expression* expr, Type* type,
- Location location)
-{
- return new Type_guard_expression(expr, type, location);
-}
-
-// Class Heap_composite_expression.
-
-// When you take the address of a composite literal, it is allocated
-// on the heap. This class implements that.
-
-class Heap_composite_expression : public Expression
-{
- public:
- Heap_composite_expression(Expression* expr, Location location)
- : Expression(EXPRESSION_HEAP_COMPOSITE, location),
- expr_(expr)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Expression::traverse(&this->expr_, traverse); }
-
- Type*
- do_type()
- { return Type::make_pointer_type(this->expr_->type()); }
-
- void
- do_determine_type(const Type_context*)
- { this->expr_->determine_type_no_context(); }
-
- Expression*
- do_copy()
- {
- return Expression::make_heap_composite(this->expr_->copy(),
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-
- // We only export global objects, and the parser does not generate
- // this in global scope.
- void
- do_export(Export*) const
- { go_unreachable(); }
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The composite literal which is being put on the heap.
- Expression* expr_;
-};
-
-// Return a tree which allocates a composite literal on the heap.
-
-tree
-Heap_composite_expression::do_get_tree(Translate_context* context)
-{
- tree expr_tree = this->expr_->get_tree(context);
- if (expr_tree == error_mark_node || TREE_TYPE(expr_tree) == error_mark_node)
- return error_mark_node;
- tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree));
- go_assert(TREE_CODE(expr_size) == INTEGER_CST);
- tree space = context->gogo()->allocate_memory(this->expr_->type(),
- expr_size, this->location());
- space = fold_convert(build_pointer_type(TREE_TYPE(expr_tree)), space);
- space = save_expr(space);
- tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
- space);
- TREE_THIS_NOTRAP(ref) = 1;
- tree ret = build2(COMPOUND_EXPR, TREE_TYPE(space),
- build2(MODIFY_EXPR, void_type_node, ref, expr_tree),
- space);
- SET_EXPR_LOCATION(ret, this->location().gcc_location());
- return ret;
-}
-
-// Dump ast representation for a heap composite expression.
-
-void
-Heap_composite_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << "&(";
- ast_dump_context->dump_expression(this->expr_);
- ast_dump_context->ostream() << ")";
-}
-
-// Allocate a composite literal on the heap.
-
-Expression*
-Expression::make_heap_composite(Expression* expr, Location location)
-{
- return new Heap_composite_expression(expr, location);
-}
-
-// Class Receive_expression.
-
-// Return the type of a receive expression.
-
-Type*
-Receive_expression::do_type()
-{
- Channel_type* channel_type = this->channel_->type()->channel_type();
- if (channel_type == NULL)
- return Type::make_error_type();
- return channel_type->element_type();
-}
-
-// Check types for a receive expression.
-
-void
-Receive_expression::do_check_types(Gogo*)
-{
- Type* type = this->channel_->type();
- if (type->is_error())
- {
- this->set_is_error();
- return;
- }
- if (type->channel_type() == NULL)
- {
- this->report_error(_("expected channel"));
- return;
- }
- if (!type->channel_type()->may_receive())
- {
- this->report_error(_("invalid receive on send-only channel"));
- return;
- }
-}
-
-// Get a tree for a receive expression.
-
-tree
-Receive_expression::do_get_tree(Translate_context* context)
-{
- Location loc = this->location();
-
- Channel_type* channel_type = this->channel_->type()->channel_type();
- if (channel_type == NULL)
- {
- go_assert(this->channel_->type()->is_error());
- return error_mark_node;
- }
-
- Expression* td = Expression::make_type_descriptor(channel_type, loc);
- tree td_tree = td->get_tree(context);
-
- Type* element_type = channel_type->element_type();
- Btype* element_type_btype = element_type->get_backend(context->gogo());
- tree element_type_tree = type_to_tree(element_type_btype);
-
- tree channel = this->channel_->get_tree(context);
- if (element_type_tree == error_mark_node || channel == error_mark_node)
- return error_mark_node;
-
- return Gogo::receive_from_channel(element_type_tree, td_tree, channel, loc);
-}
-
-// Dump ast representation for a receive expression.
-
-void
-Receive_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << " <- " ;
- ast_dump_context->dump_expression(channel_);
-}
-
-// Make a receive expression.
-
-Receive_expression*
-Expression::make_receive(Expression* channel, Location location)
-{
- return new Receive_expression(channel, location);
-}
-
-// An expression which evaluates to a pointer to the type descriptor
-// of a type.
-
-class Type_descriptor_expression : public Expression
-{
- public:
- Type_descriptor_expression(Type* type, Location location)
- : Expression(EXPRESSION_TYPE_DESCRIPTOR, location),
- type_(type)
- { }
-
- protected:
- Type*
- do_type()
- { return Type::make_type_descriptor_ptr_type(); }
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- { return this; }
-
- tree
- do_get_tree(Translate_context* context)
- {
- return this->type_->type_descriptor_pointer(context->gogo(),
- this->location());
- }
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type for which this is the descriptor.
- Type* type_;
-};
-
-// Dump ast representation for a type descriptor expression.
-
-void
-Type_descriptor_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->dump_type(this->type_);
-}
-
-// Make a type descriptor expression.
-
-Expression*
-Expression::make_type_descriptor(Type* type, Location location)
-{
- return new Type_descriptor_expression(type, location);
-}
-
-// An expression which evaluates to some characteristic of a type.
-// This is only used to initialize fields of a type descriptor. Using
-// a new expression class is slightly inefficient but gives us a good
-// separation between the frontend and the middle-end with regard to
-// how types are laid out.
-
-class Type_info_expression : public Expression
-{
- public:
- Type_info_expression(Type* type, Type_info type_info)
- : Expression(EXPRESSION_TYPE_INFO, Linemap::predeclared_location()),
- type_(type), type_info_(type_info)
- { }
-
- protected:
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- { return this; }
-
- tree
- do_get_tree(Translate_context* context);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type for which we are getting information.
- Type* type_;
- // What information we want.
- Type_info type_info_;
-};
-
-// The type is chosen to match what the type descriptor struct
-// expects.
-
-Type*
-Type_info_expression::do_type()
-{
- switch (this->type_info_)
- {
- case TYPE_INFO_SIZE:
- return Type::lookup_integer_type("uintptr");
- case TYPE_INFO_ALIGNMENT:
- case TYPE_INFO_FIELD_ALIGNMENT:
- return Type::lookup_integer_type("uint8");
- default:
- go_unreachable();
- }
-}
-
-// Return type information in GENERIC.
-
-tree
-Type_info_expression::do_get_tree(Translate_context* context)
-{
- Btype* btype = this->type_->get_backend(context->gogo());
- Gogo* gogo = context->gogo();
- size_t val;
- switch (this->type_info_)
- {
- case TYPE_INFO_SIZE:
- val = gogo->backend()->type_size(btype);
- break;
- case TYPE_INFO_ALIGNMENT:
- val = gogo->backend()->type_alignment(btype);
- break;
- case TYPE_INFO_FIELD_ALIGNMENT:
- val = gogo->backend()->type_field_alignment(btype);
- break;
- default:
- go_unreachable();
- }
- tree val_type_tree = type_to_tree(this->type()->get_backend(gogo));
- go_assert(val_type_tree != error_mark_node);
- return build_int_cstu(val_type_tree, val);
-}
-
-// Dump ast representation for a type info expression.
-
-void
-Type_info_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << "typeinfo(";
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << ",";
- ast_dump_context->ostream() <<
- (this->type_info_ == TYPE_INFO_ALIGNMENT ? "alignment"
- : this->type_info_ == TYPE_INFO_FIELD_ALIGNMENT ? "field alignment"
- : this->type_info_ == TYPE_INFO_SIZE ? "size "
- : "unknown");
- ast_dump_context->ostream() << ")";
-}
-
-// Make a type info expression.
-
-Expression*
-Expression::make_type_info(Type* type, Type_info type_info)
-{
- return new Type_info_expression(type, type_info);
-}
-
-// An expression which evaluates to the offset of a field within a
-// struct. This, like Type_info_expression, q.v., is only used to
-// initialize fields of a type descriptor.
-
-class Struct_field_offset_expression : public Expression
-{
- public:
- Struct_field_offset_expression(Struct_type* type, const Struct_field* field)
- : Expression(EXPRESSION_STRUCT_FIELD_OFFSET,
- Linemap::predeclared_location()),
- type_(type), field_(field)
- { }
-
- protected:
- Type*
- do_type()
- { return Type::lookup_integer_type("uintptr"); }
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- { return this; }
-
- tree
- do_get_tree(Translate_context* context);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type of the struct.
- Struct_type* type_;
- // The field.
- const Struct_field* field_;
-};
-
-// Return a struct field offset in GENERIC.
-
-tree
-Struct_field_offset_expression::do_get_tree(Translate_context* context)
-{
- tree type_tree = type_to_tree(this->type_->get_backend(context->gogo()));
- if (type_tree == error_mark_node)
- return error_mark_node;
-
- tree val_type_tree = type_to_tree(this->type()->get_backend(context->gogo()));
- go_assert(val_type_tree != error_mark_node);
-
- const Struct_field_list* fields = this->type_->fields();
- tree struct_field_tree = TYPE_FIELDS(type_tree);
- Struct_field_list::const_iterator p;
- for (p = fields->begin();
- p != fields->end();
- ++p, struct_field_tree = DECL_CHAIN(struct_field_tree))
- {
- go_assert(struct_field_tree != NULL_TREE);
- if (&*p == this->field_)
- break;
- }
- go_assert(&*p == this->field_);
-
- return fold_convert_loc(BUILTINS_LOCATION, val_type_tree,
- byte_position(struct_field_tree));
-}
-
-// Dump ast representation for a struct field offset expression.
-
-void
-Struct_field_offset_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << "unsafe.Offsetof(";
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << '.';
- ast_dump_context->ostream() <<
- Gogo::message_name(this->field_->field_name());
- ast_dump_context->ostream() << ")";
-}
-
-// Make an expression for a struct field offset.
-
-Expression*
-Expression::make_struct_field_offset(Struct_type* type,
- const Struct_field* field)
-{
- return new Struct_field_offset_expression(type, field);
-}
-
-// An expression which evaluates to a pointer to the map descriptor of
-// a map type.
-
-class Map_descriptor_expression : public Expression
-{
- public:
- Map_descriptor_expression(Map_type* type, Location location)
- : Expression(EXPRESSION_MAP_DESCRIPTOR, location),
- type_(type)
- { }
-
- protected:
- Type*
- do_type()
- { return Type::make_pointer_type(Map_type::make_map_descriptor_type()); }
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- { return this; }
-
- tree
- do_get_tree(Translate_context* context)
- {
- return this->type_->map_descriptor_pointer(context->gogo(),
- this->location());
- }
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type for which this is the descriptor.
- Map_type* type_;
-};
-
-// Dump ast representation for a map descriptor expression.
-
-void
-Map_descriptor_expression::do_dump_expression(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->ostream() << "map_descriptor(";
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << ")";
-}
-
-// Make a map descriptor expression.
-
-Expression*
-Expression::make_map_descriptor(Map_type* type, Location location)
-{
- return new Map_descriptor_expression(type, location);
-}
-
-// An expression which evaluates to the address of an unnamed label.
-
-class Label_addr_expression : public Expression
-{
- public:
- Label_addr_expression(Label* label, Location location)
- : Expression(EXPRESSION_LABEL_ADDR, location),
- label_(label)
- { }
-
- protected:
- Type*
- do_type()
- { return Type::make_pointer_type(Type::make_void_type()); }
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- { return new Label_addr_expression(this->label_, this->location()); }
-
- tree
- do_get_tree(Translate_context* context)
- {
- return expr_to_tree(this->label_->get_addr(context, this->location()));
- }
-
- void
- do_dump_expression(Ast_dump_context* ast_dump_context) const
- { ast_dump_context->ostream() << this->label_->name(); }
-
- private:
- // The label whose address we are taking.
- Label* label_;
-};
-
-// Make an expression for the address of an unnamed label.
-
-Expression*
-Expression::make_label_addr(Label* label, Location location)
-{
- return new Label_addr_expression(label, location);
-}
-
-// Import an expression. This comes at the end in order to see the
-// various class definitions.
-
-Expression*
-Expression::import_expression(Import* imp)
-{
- int c = imp->peek_char();
- if (imp->match_c_string("- ")
- || imp->match_c_string("! ")
- || imp->match_c_string("^ "))
- return Unary_expression::do_import(imp);
- else if (c == '(')
- return Binary_expression::do_import(imp);
- else if (imp->match_c_string("true")
- || imp->match_c_string("false"))
- return Boolean_expression::do_import(imp);
- else if (c == '"')
- return String_expression::do_import(imp);
- else if (c == '-' || (c >= '0' && c <= '9'))
- {
- // This handles integers, floats and complex constants.
- return Integer_expression::do_import(imp);
- }
- else if (imp->match_c_string("nil"))
- return Nil_expression::do_import(imp);
- else if (imp->match_c_string("convert"))
- return Type_conversion_expression::do_import(imp);
- else
- {
- error_at(imp->location(), "import error: expected expression");
- return Expression::make_error(imp->location());
- }
-}
-
-// Class Expression_list.
-
-// Traverse the list.
-
-int
-Expression_list::traverse(Traverse* traverse)
-{
- for (Expression_list::iterator p = this->begin();
- p != this->end();
- ++p)
- {
- if (*p != NULL)
- {
- if (Expression::traverse(&*p, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Copy the list.
-
-Expression_list*
-Expression_list::copy()
-{
- Expression_list* ret = new Expression_list();
- for (Expression_list::iterator p = this->begin();
- p != this->end();
- ++p)
- {
- if (*p == NULL)
- ret->push_back(NULL);
- else
- ret->push_back((*p)->copy());
- }
- return ret;
-}
-
-// Return whether an expression list has an error expression.
-
-bool
-Expression_list::contains_error() const
-{
- for (Expression_list::const_iterator p = this->begin();
- p != this->end();
- ++p)
- if (*p != NULL && (*p)->is_error_expression())
- return true;
- return false;
-}
-
-// Class Numeric_constant.
-
-// Destructor.
-
-Numeric_constant::~Numeric_constant()
-{
- this->clear();
-}
-
-// Copy constructor.
-
-Numeric_constant::Numeric_constant(const Numeric_constant& a)
- : classification_(a.classification_), type_(a.type_)
-{
- switch (a.classification_)
- {
- case NC_INVALID:
- break;
- case NC_INT:
- case NC_RUNE:
- mpz_init_set(this->u_.int_val, a.u_.int_val);
- break;
- case NC_FLOAT:
- mpfr_init_set(this->u_.float_val, a.u_.float_val, GMP_RNDN);
- break;
- case NC_COMPLEX:
- mpfr_init_set(this->u_.complex_val.real, a.u_.complex_val.real,
- GMP_RNDN);
- mpfr_init_set(this->u_.complex_val.imag, a.u_.complex_val.imag,
- GMP_RNDN);
- break;
- default:
- go_unreachable();
- }
-}
-
-// Assignment operator.
-
-Numeric_constant&
-Numeric_constant::operator=(const Numeric_constant& a)
-{
- this->clear();
- this->classification_ = a.classification_;
- this->type_ = a.type_;
- switch (a.classification_)
- {
- case NC_INVALID:
- break;
- case NC_INT:
- case NC_RUNE:
- mpz_init_set(this->u_.int_val, a.u_.int_val);
- break;
- case NC_FLOAT:
- mpfr_init_set(this->u_.float_val, a.u_.float_val, GMP_RNDN);
- break;
- case NC_COMPLEX:
- mpfr_init_set(this->u_.complex_val.real, a.u_.complex_val.real,
- GMP_RNDN);
- mpfr_init_set(this->u_.complex_val.imag, a.u_.complex_val.imag,
- GMP_RNDN);
- break;
- default:
- go_unreachable();
- }
- return *this;
-}
-
-// Clear the contents.
-
-void
-Numeric_constant::clear()
-{
- switch (this->classification_)
- {
- case NC_INVALID:
- break;
- case NC_INT:
- case NC_RUNE:
- mpz_clear(this->u_.int_val);
- break;
- case NC_FLOAT:
- mpfr_clear(this->u_.float_val);
- break;
- case NC_COMPLEX:
- mpfr_clear(this->u_.complex_val.real);
- mpfr_clear(this->u_.complex_val.imag);
- break;
- default:
- go_unreachable();
- }
- this->classification_ = NC_INVALID;
-}
-
-// Set to an unsigned long value.
-
-void
-Numeric_constant::set_unsigned_long(Type* type, unsigned long val)
-{
- this->clear();
- this->classification_ = NC_INT;
- this->type_ = type;
- mpz_init_set_ui(this->u_.int_val, val);
-}
-
-// Set to an integer value.
-
-void
-Numeric_constant::set_int(Type* type, const mpz_t val)
-{
- this->clear();
- this->classification_ = NC_INT;
- this->type_ = type;
- mpz_init_set(this->u_.int_val, val);
-}
-
-// Set to a rune value.
-
-void
-Numeric_constant::set_rune(Type* type, const mpz_t val)
-{
- this->clear();
- this->classification_ = NC_RUNE;
- this->type_ = type;
- mpz_init_set(this->u_.int_val, val);
-}
-
-// Set to a floating point value.
-
-void
-Numeric_constant::set_float(Type* type, const mpfr_t val)
-{
- this->clear();
- this->classification_ = NC_FLOAT;
- this->type_ = type;
- // Numeric constants do not have negative zero values, so remove
- // them here. They also don't have infinity or NaN values, but we
- // should never see them here.
- if (mpfr_zero_p(val))
- mpfr_init_set_ui(this->u_.float_val, 0, GMP_RNDN);
- else
- mpfr_init_set(this->u_.float_val, val, GMP_RNDN);
-}
-
-// Set to a complex value.
-
-void
-Numeric_constant::set_complex(Type* type, const mpfr_t real, const mpfr_t imag)
-{
- this->clear();
- this->classification_ = NC_COMPLEX;
- this->type_ = type;
- mpfr_init_set(this->u_.complex_val.real, real, GMP_RNDN);
- mpfr_init_set(this->u_.complex_val.imag, imag, GMP_RNDN);
-}
-
-// Get an int value.
-
-void
-Numeric_constant::get_int(mpz_t* val) const
-{
- go_assert(this->is_int());
- mpz_init_set(*val, this->u_.int_val);
-}
-
-// Get a rune value.
-
-void
-Numeric_constant::get_rune(mpz_t* val) const
-{
- go_assert(this->is_rune());
- mpz_init_set(*val, this->u_.int_val);
-}
-
-// Get a floating point value.
-
-void
-Numeric_constant::get_float(mpfr_t* val) const
-{
- go_assert(this->is_float());
- mpfr_init_set(*val, this->u_.float_val, GMP_RNDN);
-}
-
-// Get a complex value.
-
-void
-Numeric_constant::get_complex(mpfr_t* real, mpfr_t* imag) const
-{
- go_assert(this->is_complex());
- mpfr_init_set(*real, this->u_.complex_val.real, GMP_RNDN);
- mpfr_init_set(*imag, this->u_.complex_val.imag, GMP_RNDN);
-}
-
-// Express value as unsigned long if possible.
-
-Numeric_constant::To_unsigned_long
-Numeric_constant::to_unsigned_long(unsigned long* val) const
-{
- switch (this->classification_)
- {
- case NC_INT:
- case NC_RUNE:
- return this->mpz_to_unsigned_long(this->u_.int_val, val);
- case NC_FLOAT:
- return this->mpfr_to_unsigned_long(this->u_.float_val, val);
- case NC_COMPLEX:
- if (!mpfr_zero_p(this->u_.complex_val.imag))
- return NC_UL_NOTINT;
- return this->mpfr_to_unsigned_long(this->u_.complex_val.real, val);
- default:
- go_unreachable();
- }
-}
-
-// Express integer value as unsigned long if possible.
-
-Numeric_constant::To_unsigned_long
-Numeric_constant::mpz_to_unsigned_long(const mpz_t ival,
- unsigned long *val) const
-{
- if (mpz_sgn(ival) < 0)
- return NC_UL_NEGATIVE;
- unsigned long ui = mpz_get_ui(ival);
- if (mpz_cmp_ui(ival, ui) != 0)
- return NC_UL_BIG;
- *val = ui;
- return NC_UL_VALID;
-}
-
-// Express floating point value as unsigned long if possible.
-
-Numeric_constant::To_unsigned_long
-Numeric_constant::mpfr_to_unsigned_long(const mpfr_t fval,
- unsigned long *val) const
-{
- if (!mpfr_integer_p(fval))
- return NC_UL_NOTINT;
- mpz_t ival;
- mpz_init(ival);
- mpfr_get_z(ival, fval, GMP_RNDN);
- To_unsigned_long ret = this->mpz_to_unsigned_long(ival, val);
- mpz_clear(ival);
- return ret;
-}
-
-// Convert value to integer if possible.
-
-bool
-Numeric_constant::to_int(mpz_t* val) const
-{
- switch (this->classification_)
- {
- case NC_INT:
- case NC_RUNE:
- mpz_init_set(*val, this->u_.int_val);
- return true;
- case NC_FLOAT:
- if (!mpfr_integer_p(this->u_.float_val))
- return false;
- mpz_init(*val);
- mpfr_get_z(*val, this->u_.float_val, GMP_RNDN);
- return true;
- case NC_COMPLEX:
- if (!mpfr_zero_p(this->u_.complex_val.imag)
- || !mpfr_integer_p(this->u_.complex_val.real))
- return false;
- mpz_init(*val);
- mpfr_get_z(*val, this->u_.complex_val.real, GMP_RNDN);
- return true;
- default:
- go_unreachable();
- }
-}
-
-// Convert value to floating point if possible.
-
-bool
-Numeric_constant::to_float(mpfr_t* val) const
-{
- switch (this->classification_)
- {
- case NC_INT:
- case NC_RUNE:
- mpfr_init_set_z(*val, this->u_.int_val, GMP_RNDN);
- return true;
- case NC_FLOAT:
- mpfr_init_set(*val, this->u_.float_val, GMP_RNDN);
- return true;
- case NC_COMPLEX:
- if (!mpfr_zero_p(this->u_.complex_val.imag))
- return false;
- mpfr_init_set(*val, this->u_.complex_val.real, GMP_RNDN);
- return true;
- default:
- go_unreachable();
- }
-}
-
-// Convert value to complex.
-
-bool
-Numeric_constant::to_complex(mpfr_t* vr, mpfr_t* vi) const
-{
- switch (this->classification_)
- {
- case NC_INT:
- case NC_RUNE:
- mpfr_init_set_z(*vr, this->u_.int_val, GMP_RNDN);
- mpfr_init_set_ui(*vi, 0, GMP_RNDN);
- return true;
- case NC_FLOAT:
- mpfr_init_set(*vr, this->u_.float_val, GMP_RNDN);
- mpfr_init_set_ui(*vi, 0, GMP_RNDN);
- return true;
- case NC_COMPLEX:
- mpfr_init_set(*vr, this->u_.complex_val.real, GMP_RNDN);
- mpfr_init_set(*vi, this->u_.complex_val.imag, GMP_RNDN);
- return true;
- default:
- go_unreachable();
- }
-}
-
-// Get the type.
-
-Type*
-Numeric_constant::type() const
-{
- if (this->type_ != NULL)
- return this->type_;
- switch (this->classification_)
- {
- case NC_INT:
- return Type::make_abstract_integer_type();
- case NC_RUNE:
- return Type::make_abstract_character_type();
- case NC_FLOAT:
- return Type::make_abstract_float_type();
- case NC_COMPLEX:
- return Type::make_abstract_complex_type();
- default:
- go_unreachable();
- }
-}
-
-// If the constant can be expressed in TYPE, then set the type of the
-// constant to TYPE and return true. Otherwise return false, and, if
-// ISSUE_ERROR is true, report an appropriate error message.
-
-bool
-Numeric_constant::set_type(Type* type, bool issue_error, Location loc)
-{
- bool ret;
- if (type == NULL)
- ret = true;
- else if (type->integer_type() != NULL)
- ret = this->check_int_type(type->integer_type(), issue_error, loc);
- else if (type->float_type() != NULL)
- ret = this->check_float_type(type->float_type(), issue_error, loc);
- else if (type->complex_type() != NULL)
- ret = this->check_complex_type(type->complex_type(), issue_error, loc);
- else
- go_unreachable();
- if (ret)
- this->type_ = type;
- return ret;
-}
-
-// Check whether the constant can be expressed in an integer type.
-
-bool
-Numeric_constant::check_int_type(Integer_type* type, bool issue_error,
- Location location) const
-{
- mpz_t val;
- switch (this->classification_)
- {
- case NC_INT:
- case NC_RUNE:
- mpz_init_set(val, this->u_.int_val);
- break;
-
- case NC_FLOAT:
- if (!mpfr_integer_p(this->u_.float_val))
- {
- if (issue_error)
- error_at(location, "floating point constant truncated to integer");
- return false;
- }
- mpz_init(val);
- mpfr_get_z(val, this->u_.float_val, GMP_RNDN);
- break;
-
- case NC_COMPLEX:
- if (!mpfr_integer_p(this->u_.complex_val.real)
- || !mpfr_zero_p(this->u_.complex_val.imag))
- {
- if (issue_error)
- error_at(location, "complex constant truncated to integer");
- return false;
- }
- mpz_init(val);
- mpfr_get_z(val, this->u_.complex_val.real, GMP_RNDN);
- break;
-
- default:
- go_unreachable();
- }
-
- bool ret;
- if (type->is_abstract())
- ret = true;
- else
- {
- int bits = mpz_sizeinbase(val, 2);
- if (type->is_unsigned())
- {
- // For an unsigned type we can only accept a nonnegative
- // number, and we must be able to represents at least BITS.
- ret = mpz_sgn(val) >= 0 && bits <= type->bits();
- }
- else
- {
- // For a signed type we need an extra bit to indicate the
- // sign. We have to handle the most negative integer
- // specially.
- ret = (bits + 1 <= type->bits()
- || (bits <= type->bits()
- && mpz_sgn(val) < 0
- && (mpz_scan1(val, 0)
- == static_cast<unsigned long>(type->bits() - 1))
- && mpz_scan0(val, type->bits()) == ULONG_MAX));
- }
- }
-
- if (!ret && issue_error)
- error_at(location, "integer constant overflow");
-
- return ret;
-}
-
-// Check whether the constant can be expressed in a floating point
-// type.
-
-bool
-Numeric_constant::check_float_type(Float_type* type, bool issue_error,
- Location location)
-{
- mpfr_t val;
- switch (this->classification_)
- {
- case NC_INT:
- case NC_RUNE:
- mpfr_init_set_z(val, this->u_.int_val, GMP_RNDN);
- break;
-
- case NC_FLOAT:
- mpfr_init_set(val, this->u_.float_val, GMP_RNDN);
- break;
-
- case NC_COMPLEX:
- if (!mpfr_zero_p(this->u_.complex_val.imag))
- {
- if (issue_error)
- error_at(location, "complex constant truncated to float");
- return false;
- }
- mpfr_init_set(val, this->u_.complex_val.real, GMP_RNDN);
- break;
-
- default:
- go_unreachable();
- }
-
- bool ret;
- if (type->is_abstract())
- ret = true;
- else if (mpfr_nan_p(val) || mpfr_inf_p(val) || mpfr_zero_p(val))
- {
- // A NaN or Infinity always fits in the range of the type.
- ret = true;
- }
- else
- {
- mp_exp_t exp = mpfr_get_exp(val);
- mp_exp_t max_exp;
- switch (type->bits())
- {
- case 32:
- max_exp = 128;
- break;
- case 64:
- max_exp = 1024;
- break;
- default:
- go_unreachable();
- }
-
- ret = exp <= max_exp;
-
- if (ret)
- {
- // Round the constant to the desired type.
- mpfr_t t;
- mpfr_init(t);
- switch (type->bits())
- {
- case 32:
- mpfr_set_prec(t, 24);
- break;
- case 64:
- mpfr_set_prec(t, 53);
- break;
- default:
- go_unreachable();
- }
- mpfr_set(t, val, GMP_RNDN);
- mpfr_set(val, t, GMP_RNDN);
- mpfr_clear(t);
-
- this->set_float(type, val);
- }
- }
-
- mpfr_clear(val);
-
- if (!ret && issue_error)
- error_at(location, "floating point constant overflow");
-
- return ret;
-}
-
-// Check whether the constant can be expressed in a complex type.
-
-bool
-Numeric_constant::check_complex_type(Complex_type* type, bool issue_error,
- Location location)
-{
- if (type->is_abstract())
- return true;
-
- mp_exp_t max_exp;
- switch (type->bits())
- {
- case 64:
- max_exp = 128;
- break;
- case 128:
- max_exp = 1024;
- break;
- default:
- go_unreachable();
- }
-
- mpfr_t real;
- mpfr_t imag;
- switch (this->classification_)
- {
- case NC_INT:
- case NC_RUNE:
- mpfr_init_set_z(real, this->u_.int_val, GMP_RNDN);
- mpfr_init_set_ui(imag, 0, GMP_RNDN);
- break;
-
- case NC_FLOAT:
- mpfr_init_set(real, this->u_.float_val, GMP_RNDN);
- mpfr_init_set_ui(imag, 0, GMP_RNDN);
- break;
-
- case NC_COMPLEX:
- mpfr_init_set(real, this->u_.complex_val.real, GMP_RNDN);
- mpfr_init_set(imag, this->u_.complex_val.imag, GMP_RNDN);
- break;
-
- default:
- go_unreachable();
- }
-
- bool ret = true;
- if (!mpfr_nan_p(real)
- && !mpfr_inf_p(real)
- && !mpfr_zero_p(real)
- && mpfr_get_exp(real) > max_exp)
- {
- if (issue_error)
- error_at(location, "complex real part overflow");
- ret = false;
- }
-
- if (!mpfr_nan_p(imag)
- && !mpfr_inf_p(imag)
- && !mpfr_zero_p(imag)
- && mpfr_get_exp(imag) > max_exp)
- {
- if (issue_error)
- error_at(location, "complex imaginary part overflow");
- ret = false;
- }
-
- if (ret)
- {
- // Round the constant to the desired type.
- mpfr_t t;
- mpfr_init(t);
- switch (type->bits())
- {
- case 64:
- mpfr_set_prec(t, 24);
- break;
- case 128:
- mpfr_set_prec(t, 53);
- break;
- default:
- go_unreachable();
- }
- mpfr_set(t, real, GMP_RNDN);
- mpfr_set(real, t, GMP_RNDN);
- mpfr_set(t, imag, GMP_RNDN);
- mpfr_set(imag, t, GMP_RNDN);
- mpfr_clear(t);
-
- this->set_complex(type, real, imag);
- }
-
- mpfr_clear(real);
- mpfr_clear(imag);
-
- return ret;
-}
-
-// Return an Expression for this value.
-
-Expression*
-Numeric_constant::expression(Location loc) const
-{
- switch (this->classification_)
- {
- case NC_INT:
- return Expression::make_integer(&this->u_.int_val, this->type_, loc);
- case NC_RUNE:
- return Expression::make_character(&this->u_.int_val, this->type_, loc);
- case NC_FLOAT:
- return Expression::make_float(&this->u_.float_val, this->type_, loc);
- case NC_COMPLEX:
- return Expression::make_complex(&this->u_.complex_val.real,
- &this->u_.complex_val.imag,
- this->type_, loc);
- default:
- go_unreachable();
- }
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/expressions.h b/gcc-4.8.1/gcc/go/gofrontend/expressions.h
deleted file mode 100644
index af178de5c..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/expressions.h
+++ /dev/null
@@ -1,2268 +0,0 @@
-// expressions.h -- Go frontend expression handling. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_EXPRESSIONS_H
-#define GO_EXPRESSIONS_H
-
-#include <mpfr.h>
-
-#include "operator.h"
-
-class Gogo;
-class Translate_context;
-class Traverse;
-class Statement_inserter;
-class Type;
-struct Type_context;
-class Integer_type;
-class Float_type;
-class Complex_type;
-class Function_type;
-class Map_type;
-class Struct_type;
-class Struct_field;
-class Expression_list;
-class Var_expression;
-class Temporary_reference_expression;
-class Set_and_use_temporary_expression;
-class String_expression;
-class Binary_expression;
-class Call_expression;
-class Func_expression;
-class Unknown_expression;
-class Index_expression;
-class Map_index_expression;
-class Bound_method_expression;
-class Field_reference_expression;
-class Interface_field_reference_expression;
-class Type_guard_expression;
-class Receive_expression;
-class Numeric_constant;
-class Named_object;
-class Export;
-class Import;
-class Temporary_statement;
-class Label;
-class Ast_dump_context;
-class String_dump;
-
-// The base class for all expressions.
-
-class Expression
-{
- public:
- // The types of expressions.
- enum Expression_classification
- {
- EXPRESSION_ERROR,
- EXPRESSION_TYPE,
- EXPRESSION_UNARY,
- EXPRESSION_BINARY,
- EXPRESSION_CONST_REFERENCE,
- EXPRESSION_VAR_REFERENCE,
- EXPRESSION_TEMPORARY_REFERENCE,
- EXPRESSION_SET_AND_USE_TEMPORARY,
- EXPRESSION_SINK,
- EXPRESSION_FUNC_REFERENCE,
- EXPRESSION_UNKNOWN_REFERENCE,
- EXPRESSION_BOOLEAN,
- EXPRESSION_STRING,
- EXPRESSION_INTEGER,
- EXPRESSION_FLOAT,
- EXPRESSION_COMPLEX,
- EXPRESSION_NIL,
- EXPRESSION_IOTA,
- EXPRESSION_CALL,
- EXPRESSION_CALL_RESULT,
- EXPRESSION_BOUND_METHOD,
- EXPRESSION_INDEX,
- EXPRESSION_ARRAY_INDEX,
- EXPRESSION_STRING_INDEX,
- EXPRESSION_MAP_INDEX,
- EXPRESSION_SELECTOR,
- EXPRESSION_FIELD_REFERENCE,
- EXPRESSION_INTERFACE_FIELD_REFERENCE,
- EXPRESSION_ALLOCATION,
- EXPRESSION_TYPE_GUARD,
- EXPRESSION_CONVERSION,
- EXPRESSION_UNSAFE_CONVERSION,
- EXPRESSION_STRUCT_CONSTRUCTION,
- EXPRESSION_FIXED_ARRAY_CONSTRUCTION,
- EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
- EXPRESSION_MAP_CONSTRUCTION,
- EXPRESSION_COMPOSITE_LITERAL,
- EXPRESSION_HEAP_COMPOSITE,
- EXPRESSION_RECEIVE,
- EXPRESSION_TYPE_DESCRIPTOR,
- EXPRESSION_TYPE_INFO,
- EXPRESSION_STRUCT_FIELD_OFFSET,
- EXPRESSION_MAP_DESCRIPTOR,
- EXPRESSION_LABEL_ADDR
- };
-
- Expression(Expression_classification, Location);
-
- virtual ~Expression();
-
- // Make an error expression. This is used when a parse error occurs
- // to prevent cascading errors.
- static Expression*
- make_error(Location);
-
- // Make an expression which is really a type. This is used during
- // parsing.
- static Expression*
- make_type(Type*, Location);
-
- // Make a unary expression.
- static Expression*
- make_unary(Operator, Expression*, Location);
-
- // Make a binary expression.
- static Expression*
- make_binary(Operator, Expression*, Expression*, Location);
-
- // Make a reference to a constant in an expression.
- static Expression*
- make_const_reference(Named_object*, Location);
-
- // Make a reference to a variable in an expression.
- static Expression*
- make_var_reference(Named_object*, Location);
-
- // Make a reference to a temporary variable. Temporary variables
- // are always created by a single statement, which is what we use to
- // refer to them.
- static Temporary_reference_expression*
- make_temporary_reference(Temporary_statement*, Location);
-
- // Make an expressions which sets a temporary variable and then
- // evaluates to a reference to that temporary variable. This is
- // used to set a temporary variable while retaining the order of
- // evaluation.
- static Set_and_use_temporary_expression*
- make_set_and_use_temporary(Temporary_statement*, Expression*, Location);
-
- // Make a sink expression--a reference to the blank identifier _.
- static Expression*
- make_sink(Location);
-
- // Make a reference to a function in an expression.
- static Expression*
- make_func_reference(Named_object*, Expression* closure, Location);
-
- // Make a reference to an unknown name. In a correct program this
- // will always be lowered to a real const/var/func reference.
- static Unknown_expression*
- make_unknown_reference(Named_object*, Location);
-
- // Make a constant bool expression.
- static Expression*
- make_boolean(bool val, Location);
-
- // Make a constant string expression.
- static Expression*
- make_string(const std::string&, Location);
-
- // Make a character constant expression. TYPE should be NULL for an
- // abstract type.
- static Expression*
- make_character(const mpz_t*, Type*, Location);
-
- // Make a constant integer expression. TYPE should be NULL for an
- // abstract type.
- static Expression*
- make_integer(const mpz_t*, Type*, Location);
-
- // Make a constant float expression. TYPE should be NULL for an
- // abstract type.
- static Expression*
- make_float(const mpfr_t*, Type*, Location);
-
- // Make a constant complex expression. TYPE should be NULL for an
- // abstract type.
- static Expression*
- make_complex(const mpfr_t* real, const mpfr_t* imag, Type*, Location);
-
- // Make a nil expression.
- static Expression*
- make_nil(Location);
-
- // Make an iota expression. This is used for the predeclared
- // constant iota.
- static Expression*
- make_iota();
-
- // Make a call expression.
- static Call_expression*
- make_call(Expression* func, Expression_list* args, bool is_varargs,
- Location);
-
- // Make a reference to a specific result of a call expression which
- // returns a tuple.
- static Expression*
- make_call_result(Call_expression*, unsigned int index);
-
- // Make an expression which is a method bound to its first
- // parameter.
- static Bound_method_expression*
- make_bound_method(Expression* object, Named_object* method, Location);
-
- // Make an index or slice expression. This is a parser expression
- // which represents LEFT[START:END]. END may be NULL, meaning an
- // index rather than a slice. At parse time we may not know the
- // type of LEFT. After parsing this is lowered to an array index, a
- // string index, or a map index.
- static Expression*
- make_index(Expression* left, Expression* start, Expression* end,
- Location);
-
- // Make an array index expression. END may be NULL, in which case
- // this is an lvalue.
- static Expression*
- make_array_index(Expression* array, Expression* start, Expression* end,
- Location);
-
- // Make a string index expression. END may be NULL. This is never
- // an lvalue.
- static Expression*
- make_string_index(Expression* string, Expression* start, Expression* end,
- Location);
-
- // Make a map index expression. This is an lvalue.
- static Map_index_expression*
- make_map_index(Expression* map, Expression* val, Location);
-
- // Make a selector. This is a parser expression which represents
- // LEFT.NAME. At parse time we may not know the type of the left
- // hand side.
- static Expression*
- make_selector(Expression* left, const std::string& name, Location);
-
- // Make a reference to a field in a struct.
- static Field_reference_expression*
- make_field_reference(Expression*, unsigned int field_index, Location);
-
- // Make a reference to a field of an interface, with an associated
- // object.
- static Expression*
- make_interface_field_reference(Expression*, const std::string&,
- Location);
-
- // Make an allocation expression.
- static Expression*
- make_allocation(Type*, Location);
-
- // Make a type guard expression.
- static Expression*
- make_type_guard(Expression*, Type*, Location);
-
- // Make a type cast expression.
- static Expression*
- make_cast(Type*, Expression*, Location);
-
- // Make an unsafe type cast expression. This is only used when
- // passing parameter to builtin functions that are part of the Go
- // runtime.
- static Expression*
- make_unsafe_cast(Type*, Expression*, Location);
-
- // Make a composite literal. The DEPTH parameter is how far down we
- // are in a list of composite literals with omitted types.
- static Expression*
- make_composite_literal(Type*, int depth, bool has_keys, Expression_list*,
- Location);
-
- // Make a struct composite literal.
- static Expression*
- make_struct_composite_literal(Type*, Expression_list*, Location);
-
- // Make a slice composite literal.
- static Expression*
- make_slice_composite_literal(Type*, Expression_list*, Location);
-
- // Take a composite literal and allocate it on the heap.
- static Expression*
- make_heap_composite(Expression*, Location);
-
- // Make a receive expression. VAL is NULL for a unary receive.
- static Receive_expression*
- make_receive(Expression* channel, Location);
-
- // Make an expression which evaluates to the address of the type
- // descriptor for TYPE.
- static Expression*
- make_type_descriptor(Type* type, Location);
-
- // Make an expression which evaluates to some characteristic of a
- // type. These are only used for type descriptors, so there is no
- // location parameter.
- enum Type_info
- {
- // The size of a value of the type.
- TYPE_INFO_SIZE,
- // The required alignment of a value of the type.
- TYPE_INFO_ALIGNMENT,
- // The required alignment of a value of the type when used as a
- // field in a struct.
- TYPE_INFO_FIELD_ALIGNMENT
- };
-
- static Expression*
- make_type_info(Type* type, Type_info);
-
- // Make an expression which evaluates to the offset of a field in a
- // struct. This is only used for type descriptors, so there is no
- // location parameter.
- static Expression*
- make_struct_field_offset(Struct_type*, const Struct_field*);
-
- // Make an expression which evaluates to the address of the map
- // descriptor for TYPE.
- static Expression*
- make_map_descriptor(Map_type* type, Location);
-
- // Make an expression which evaluates to the address of an unnamed
- // label.
- static Expression*
- make_label_addr(Label*, Location);
-
- // Return the expression classification.
- Expression_classification
- classification() const
- { return this->classification_; }
-
- // Return the location of the expression.
- Location
- location() const
- { return this->location_; }
-
- // Return whether this is a constant expression.
- bool
- is_constant() const
- { return this->do_is_constant(); }
-
- // If this is not a numeric constant, return false. If it is one,
- // return true, and set VAL to hold the value.
- bool
- numeric_constant_value(Numeric_constant* val) const
- { return this->do_numeric_constant_value(val); }
-
- // If this is not a constant expression with string type, return
- // false. If it is one, return true, and set VAL to the value.
- bool
- string_constant_value(std::string* val) const
- { return this->do_string_constant_value(val); }
-
- // This is called if the value of this expression is being
- // discarded. This issues warnings about computed values being
- // unused. This returns true if all is well, false if it issued an
- // error message.
- bool
- discarding_value()
- { return this->do_discarding_value(); }
-
- // Return whether this is an error expression.
- bool
- is_error_expression() const
- { return this->classification_ == EXPRESSION_ERROR; }
-
- // Return whether this expression really represents a type.
- bool
- is_type_expression() const
- { return this->classification_ == EXPRESSION_TYPE; }
-
- // If this is a variable reference, return the Var_expression
- // structure. Otherwise, return NULL. This is a controlled dynamic
- // cast.
- Var_expression*
- var_expression()
- { return this->convert<Var_expression, EXPRESSION_VAR_REFERENCE>(); }
-
- const Var_expression*
- var_expression() const
- { return this->convert<const Var_expression, EXPRESSION_VAR_REFERENCE>(); }
-
- // If this is a reference to a temporary variable, return the
- // Temporary_reference_expression. Otherwise, return NULL.
- Temporary_reference_expression*
- temporary_reference_expression()
- {
- return this->convert<Temporary_reference_expression,
- EXPRESSION_TEMPORARY_REFERENCE>();
- }
-
- // If this is a set-and-use-temporary, return the
- // Set_and_use_temporary_expression. Otherwise, return NULL.
- Set_and_use_temporary_expression*
- set_and_use_temporary_expression()
- {
- return this->convert<Set_and_use_temporary_expression,
- EXPRESSION_SET_AND_USE_TEMPORARY>();
- }
-
- // Return whether this is a sink expression.
- bool
- is_sink_expression() const
- { return this->classification_ == EXPRESSION_SINK; }
-
- // If this is a string expression, return the String_expression
- // structure. Otherwise, return NULL.
- String_expression*
- string_expression()
- { return this->convert<String_expression, EXPRESSION_STRING>(); }
-
- // Return whether this is the expression nil.
- bool
- is_nil_expression() const
- { return this->classification_ == EXPRESSION_NIL; }
-
- // If this is an indirection through a pointer, return the
- // expression being pointed through. Otherwise return this.
- Expression*
- deref();
-
- // If this is a binary expression, return the Binary_expression
- // structure. Otherwise return NULL.
- Binary_expression*
- binary_expression()
- { return this->convert<Binary_expression, EXPRESSION_BINARY>(); }
-
- // If this is a call expression, return the Call_expression
- // structure. Otherwise, return NULL. This is a controlled dynamic
- // cast.
- Call_expression*
- call_expression()
- { return this->convert<Call_expression, EXPRESSION_CALL>(); }
-
- // If this is an expression which refers to a function, return the
- // Func_expression structure. Otherwise, return NULL.
- Func_expression*
- func_expression()
- { return this->convert<Func_expression, EXPRESSION_FUNC_REFERENCE>(); }
-
- const Func_expression*
- func_expression() const
- { return this->convert<const Func_expression, EXPRESSION_FUNC_REFERENCE>(); }
-
- // If this is an expression which refers to an unknown name, return
- // the Unknown_expression structure. Otherwise, return NULL.
- Unknown_expression*
- unknown_expression()
- { return this->convert<Unknown_expression, EXPRESSION_UNKNOWN_REFERENCE>(); }
-
- const Unknown_expression*
- unknown_expression() const
- {
- return this->convert<const Unknown_expression,
- EXPRESSION_UNKNOWN_REFERENCE>();
- }
-
- // If this is an index expression, return the Index_expression
- // structure. Otherwise, return NULL.
- Index_expression*
- index_expression()
- { return this->convert<Index_expression, EXPRESSION_INDEX>(); }
-
- // If this is an expression which refers to indexing in a map,
- // return the Map_index_expression structure. Otherwise, return
- // NULL.
- Map_index_expression*
- map_index_expression()
- { return this->convert<Map_index_expression, EXPRESSION_MAP_INDEX>(); }
-
- // If this is a bound method expression, return the
- // Bound_method_expression structure. Otherwise, return NULL.
- Bound_method_expression*
- bound_method_expression()
- { return this->convert<Bound_method_expression, EXPRESSION_BOUND_METHOD>(); }
-
- // If this is a reference to a field in a struct, return the
- // Field_reference_expression structure. Otherwise, return NULL.
- Field_reference_expression*
- field_reference_expression()
- {
- return this->convert<Field_reference_expression,
- EXPRESSION_FIELD_REFERENCE>();
- }
-
- // If this is a reference to a field in an interface, return the
- // Interface_field_reference_expression structure. Otherwise,
- // return NULL.
- Interface_field_reference_expression*
- interface_field_reference_expression()
- {
- return this->convert<Interface_field_reference_expression,
- EXPRESSION_INTERFACE_FIELD_REFERENCE>();
- }
-
- // If this is a type guard expression, return the
- // Type_guard_expression structure. Otherwise, return NULL.
- Type_guard_expression*
- type_guard_expression()
- { return this->convert<Type_guard_expression, EXPRESSION_TYPE_GUARD>(); }
-
- // If this is a receive expression, return the Receive_expression
- // structure. Otherwise, return NULL.
- Receive_expression*
- receive_expression()
- { return this->convert<Receive_expression, EXPRESSION_RECEIVE>(); }
-
- // Return true if this is a composite literal.
- bool
- is_composite_literal() const;
-
- // Return true if this is a composite literal which is not constant.
- bool
- is_nonconstant_composite_literal() const;
-
- // Return true if this is a reference to a local variable.
- bool
- is_local_variable() const;
-
- // Traverse an expression.
- static int
- traverse(Expression**, Traverse*);
-
- // Traverse subexpressions of this expression.
- int
- traverse_subexpressions(Traverse*);
-
- // Lower an expression. This is called immediately after parsing.
- // FUNCTION is the function we are in; it will be NULL for an
- // expression initializing a global variable. INSERTER may be used
- // to insert statements before the statement or initializer
- // containing this expression; it is normally used to create
- // temporary variables. IOTA_VALUE is the value that we should give
- // to any iota expressions. This function must resolve expressions
- // which could not be fully parsed into their final form. It
- // returns the same Expression or a new one.
- Expression*
- lower(Gogo* gogo, Named_object* function, Statement_inserter* inserter,
- int iota_value)
- { return this->do_lower(gogo, function, inserter, iota_value); }
-
- // Determine the real type of an expression with abstract integer,
- // floating point, or complex type. TYPE_CONTEXT describes the
- // expected type.
- void
- determine_type(const Type_context*);
-
- // Check types in an expression.
- void
- check_types(Gogo* gogo)
- { this->do_check_types(gogo); }
-
- // Determine the type when there is no context.
- void
- determine_type_no_context();
-
- // Return the current type of the expression. This may be changed
- // by determine_type.
- Type*
- type()
- { return this->do_type(); }
-
- // Return a copy of an expression.
- Expression*
- copy()
- { return this->do_copy(); }
-
- // Return whether the expression is addressable--something which may
- // be used as the operand of the unary & operator.
- bool
- is_addressable() const
- { return this->do_is_addressable(); }
-
- // Note that we are taking the address of this expression. ESCAPES
- // is true if this address escapes the current function.
- void
- address_taken(bool escapes)
- { this->do_address_taken(escapes); }
-
- // Return whether this expression must be evaluated in order
- // according to the order of evaluation rules. This is basically
- // true of all expressions with side-effects.
- bool
- must_eval_in_order() const
- { return this->do_must_eval_in_order(); }
-
- // Return whether subexpressions of this expression must be
- // evaluated in order. This is true of index expressions and
- // pointer indirections. This sets *SKIP to the number of
- // subexpressions to skip during traversing, as index expressions
- // only requiring moving the index, not the array.
- bool
- must_eval_subexpressions_in_order(int* skip) const
- {
- *skip = 0;
- return this->do_must_eval_subexpressions_in_order(skip);
- }
-
- // Return the tree for this expression.
- tree
- get_tree(Translate_context*);
-
- // Return a tree handling any conversions which must be done during
- // assignment.
- static tree
- convert_for_assignment(Translate_context*, Type* lhs_type, Type* rhs_type,
- tree rhs_tree, Location location);
-
- // Return a tree converting a value of one interface type to another
- // interface type. If FOR_TYPE_GUARD is true this is for a type
- // assertion.
- static tree
- convert_interface_to_interface(Translate_context*, Type* lhs_type,
- Type* rhs_type, tree rhs_tree,
- bool for_type_guard, Location);
-
- // Return a tree implementing the comparison LHS_TREE OP RHS_TREE.
- // TYPE is the type of both sides.
- static tree
- comparison_tree(Translate_context*, Type* result_type, Operator op,
- Type* left_type, tree left_tree, Type* right_type,
- tree right_tree, Location);
-
- // Return a tree for the multi-precision integer VAL in TYPE.
- static tree
- integer_constant_tree(mpz_t val, tree type);
-
- // Return a tree for the floating point value VAL in TYPE.
- static tree
- float_constant_tree(mpfr_t val, tree type);
-
- // Return a tree for the complex value REAL/IMAG in TYPE.
- static tree
- complex_constant_tree(mpfr_t real, mpfr_t imag, tree type);
-
- // Export the expression. This is only used for constants. It will
- // be used for things like values of named constants and sizes of
- // arrays.
- void
- export_expression(Export* exp) const
- { this->do_export(exp); }
-
- // Import an expression.
- static Expression*
- import_expression(Import*);
-
- // Return a tree which checks that VAL, of arbitrary integer type,
- // is non-negative and is not more than the maximum value of
- // BOUND_TYPE. If SOFAR is not NULL, it is or'red into the result.
- // The return value may be NULL if SOFAR is NULL.
- static tree
- check_bounds(tree val, tree bound_type, tree sofar, Location);
-
- // Dump an expression to a dump constext.
- void
- dump_expression(Ast_dump_context*) const;
-
- protected:
- // May be implemented by child class: traverse the expressions.
- virtual int
- do_traverse(Traverse*);
-
- // Return a lowered expression.
- virtual Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int)
- { return this; }
-
- // Return whether this is a constant expression.
- virtual bool
- do_is_constant() const
- { return false; }
-
- // Return whether this is a constant expression of numeric type, and
- // set the Numeric_constant to the value.
- virtual bool
- do_numeric_constant_value(Numeric_constant*) const
- { return false; }
-
- // Return whether this is a constant expression of string type, and
- // set VAL to the value.
- virtual bool
- do_string_constant_value(std::string*) const
- { return false; }
-
- // Called by the parser if the value is being discarded.
- virtual bool
- do_discarding_value();
-
- // Child class holds type.
- virtual Type*
- do_type() = 0;
-
- // Child class implements determining type information.
- virtual void
- do_determine_type(const Type_context*) = 0;
-
- // Child class implements type checking if needed.
- virtual void
- do_check_types(Gogo*)
- { }
-
- // Child class implements copying.
- virtual Expression*
- do_copy() = 0;
-
- // Child class implements whether the expression is addressable.
- virtual bool
- do_is_addressable() const
- { return false; }
-
- // Child class implements taking the address of an expression.
- virtual void
- do_address_taken(bool)
- { }
-
- // Child class implements whether this expression must be evaluated
- // in order.
- virtual bool
- do_must_eval_in_order() const
- { return false; }
-
- // Child class implements whether this expressions requires that
- // subexpressions be evaluated in order. The child implementation
- // may set *SKIP if it should be non-zero.
- virtual bool
- do_must_eval_subexpressions_in_order(int* /* skip */) const
- { return false; }
-
- // Child class implements conversion to tree.
- virtual tree
- do_get_tree(Translate_context*) = 0;
-
- // Child class implements export.
- virtual void
- do_export(Export*) const;
-
- // For children to call to give an error for an unused value.
- void
- unused_value_error();
-
- // For children to call when they detect that they are in error.
- void
- set_is_error();
-
- // For children to call to report an error conveniently.
- void
- report_error(const char*);
-
- // Child class implements dumping to a dump context.
- virtual void
- do_dump_expression(Ast_dump_context*) const = 0;
-
- private:
- // Convert to the desired statement classification, or return NULL.
- // This is a controlled dynamic cast.
- template<typename Expression_class,
- Expression_classification expr_classification>
- Expression_class*
- convert()
- {
- return (this->classification_ == expr_classification
- ? static_cast<Expression_class*>(this)
- : NULL);
- }
-
- template<typename Expression_class,
- Expression_classification expr_classification>
- const Expression_class*
- convert() const
- {
- return (this->classification_ == expr_classification
- ? static_cast<const Expression_class*>(this)
- : NULL);
- }
-
- static tree
- convert_type_to_interface(Translate_context*, Type*, Type*, tree,
- Location);
-
- static tree
- get_interface_type_descriptor(Translate_context*, Type*, tree,
- Location);
-
- static tree
- convert_interface_to_type(Translate_context*, Type*, Type*, tree,
- Location);
-
- // The expression classification.
- Expression_classification classification_;
- // The location in the input file.
- Location location_;
-};
-
-// A list of Expressions.
-
-class Expression_list
-{
- public:
- Expression_list()
- : entries_()
- { }
-
- // Return whether the list is empty.
- bool
- empty() const
- { return this->entries_.empty(); }
-
- // Return the number of entries in the list.
- size_t
- size() const
- { return this->entries_.size(); }
-
- // Add an entry to the end of the list.
- void
- push_back(Expression* expr)
- { this->entries_.push_back(expr); }
-
- void
- append(Expression_list* add)
- { this->entries_.insert(this->entries_.end(), add->begin(), add->end()); }
-
- // Reserve space in the list.
- void
- reserve(size_t size)
- { this->entries_.reserve(size); }
-
- // Traverse the expressions in the list.
- int
- traverse(Traverse*);
-
- // Copy the list.
- Expression_list*
- copy();
-
- // Return true if the list contains an error expression.
- bool
- contains_error() const;
-
- // Retrieve an element by index.
- Expression*&
- at(size_t i)
- { return this->entries_.at(i); }
-
- // Return the first and last elements.
- Expression*&
- front()
- { return this->entries_.front(); }
-
- Expression*
- front() const
- { return this->entries_.front(); }
-
- Expression*&
- back()
- { return this->entries_.back(); }
-
- Expression*
- back() const
- { return this->entries_.back(); }
-
- // Iterators.
-
- typedef std::vector<Expression*>::iterator iterator;
- typedef std::vector<Expression*>::const_iterator const_iterator;
-
- iterator
- begin()
- { return this->entries_.begin(); }
-
- const_iterator
- begin() const
- { return this->entries_.begin(); }
-
- iterator
- end()
- { return this->entries_.end(); }
-
- const_iterator
- end() const
- { return this->entries_.end(); }
-
- // Erase an entry.
- void
- erase(iterator p)
- { this->entries_.erase(p); }
-
- private:
- std::vector<Expression*> entries_;
-};
-
-// An abstract base class for an expression which is only used by the
-// parser, and is lowered in the lowering pass.
-
-class Parser_expression : public Expression
-{
- public:
- Parser_expression(Expression_classification classification,
- Location location)
- : Expression(classification, location)
- { }
-
- protected:
- virtual Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0;
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*)
- { go_unreachable(); }
-
- void
- do_check_types(Gogo*)
- { go_unreachable(); }
-
- tree
- do_get_tree(Translate_context*)
- { go_unreachable(); }
-};
-
-// An expression which is simply a variable.
-
-class Var_expression : public Expression
-{
- public:
- Var_expression(Named_object* variable, Location location)
- : Expression(EXPRESSION_VAR_REFERENCE, location),
- variable_(variable)
- { }
-
- // Return the variable.
- Named_object*
- named_object() const
- { return this->variable_; }
-
- protected:
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- Expression*
- do_copy()
- { return this; }
-
- bool
- do_is_addressable() const
- { return true; }
-
- void
- do_address_taken(bool);
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The variable we are referencing.
- Named_object* variable_;
-};
-
-// A reference to a temporary variable.
-
-class Temporary_reference_expression : public Expression
-{
- public:
- Temporary_reference_expression(Temporary_statement* statement,
- Location location)
- : Expression(EXPRESSION_TEMPORARY_REFERENCE, location),
- statement_(statement), is_lvalue_(false)
- { }
-
- // The temporary that this expression refers to.
- Temporary_statement*
- statement() const
- { return this->statement_; }
-
- // Indicate that this reference appears on the left hand side of an
- // assignment statement.
- void
- set_is_lvalue()
- { this->is_lvalue_ = true; }
-
- protected:
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- { return make_temporary_reference(this->statement_, this->location()); }
-
- bool
- do_is_addressable() const
- { return true; }
-
- void
- do_address_taken(bool);
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The statement where the temporary variable is defined.
- Temporary_statement* statement_;
- // Whether this reference appears on the left hand side of an
- // assignment statement.
- bool is_lvalue_;
-};
-
-// Set and use a temporary variable.
-
-class Set_and_use_temporary_expression : public Expression
-{
- public:
- Set_and_use_temporary_expression(Temporary_statement* statement,
- Expression* expr, Location location)
- : Expression(EXPRESSION_SET_AND_USE_TEMPORARY, location),
- statement_(statement), expr_(expr)
- { }
-
- // Return the temporary.
- Temporary_statement*
- temporary() const
- { return this->statement_; }
-
- // Return the expression.
- Expression*
- expression() const
- { return this->expr_; }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Expression::traverse(&this->expr_, traverse); }
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- {
- return make_set_and_use_temporary(this->statement_, this->expr_,
- this->location());
- }
-
- bool
- do_is_addressable() const
- { return true; }
-
- void
- do_address_taken(bool);
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The statement where the temporary variable is defined.
- Temporary_statement* statement_;
- // The expression to assign to the temporary.
- Expression* expr_;
-};
-
-// A string expression.
-
-class String_expression : public Expression
-{
- public:
- String_expression(const std::string& val, Location location)
- : Expression(EXPRESSION_STRING, location),
- val_(val), type_(NULL)
- { }
-
- const std::string&
- val() const
- { return this->val_; }
-
- static Expression*
- do_import(Import*);
-
- protected:
- bool
- do_is_constant() const
- { return true; }
-
- bool
- do_string_constant_value(std::string* val) const
- {
- *val = this->val_;
- return true;
- }
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- Expression*
- do_copy()
- { return this; }
-
- tree
- do_get_tree(Translate_context*);
-
- // Write string literal to a string dump.
- static void
- export_string(String_dump* exp, const String_expression* str);
-
- void
- do_export(Export*) const;
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The string value. This is immutable.
- const std::string val_;
- // The type as determined by context.
- Type* type_;
-};
-
-// A binary expression.
-
-class Binary_expression : public Expression
-{
- public:
- Binary_expression(Operator op, Expression* left, Expression* right,
- Location location)
- : Expression(EXPRESSION_BINARY, location),
- op_(op), left_(left), right_(right), type_(NULL)
- { }
-
- // Return the operator.
- Operator
- op()
- { return this->op_; }
-
- // Return the left hand expression.
- Expression*
- left()
- { return this->left_; }
-
- // Return the right hand expression.
- Expression*
- right()
- { return this->right_; }
-
- // Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC.
- // Return true if this could be done, false if not. Issue errors at
- // LOCATION as appropriate.
- static bool
- eval_constant(Operator op, Numeric_constant* left_nc,
- Numeric_constant* right_nc, Location location,
- Numeric_constant* nc);
-
- // Compare constants LEFT_NC and RIGHT_NC according to OP, setting
- // *RESULT. Return true if this could be done, false if not. Issue
- // errors at LOCATION as appropriate.
- static bool
- compare_constant(Operator op, Numeric_constant* left_nc,
- Numeric_constant* right_nc, Location location,
- bool* result);
-
- static Expression*
- do_import(Import*);
-
- // Report an error if OP can not be applied to TYPE. Return whether
- // it can. OTYPE is the type of the other operand.
- static bool
- check_operator_type(Operator op, Type* type, Type* otype, Location);
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- bool
- do_is_constant() const
- { return this->left_->is_constant() && this->right_->is_constant(); }
-
- bool
- do_numeric_constant_value(Numeric_constant*) const;
-
- bool
- do_discarding_value();
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_binary(this->op_, this->left_->copy(),
- this->right_->copy(), this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_export(Export*) const;
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- static bool
- operation_type(Operator op, Type* left_type, Type* right_type,
- Type** result_type);
-
- static bool
- cmp_to_bool(Operator op, int cmp);
-
- static bool
- eval_integer(Operator op, const Numeric_constant*, const Numeric_constant*,
- Location, Numeric_constant*);
-
- static bool
- eval_float(Operator op, const Numeric_constant*, const Numeric_constant*,
- Location, Numeric_constant*);
-
- static bool
- eval_complex(Operator op, const Numeric_constant*, const Numeric_constant*,
- Location, Numeric_constant*);
-
- static bool
- compare_integer(const Numeric_constant*, const Numeric_constant*, int*);
-
- static bool
- compare_float(const Numeric_constant*, const Numeric_constant *, int*);
-
- static bool
- compare_complex(const Numeric_constant*, const Numeric_constant*, int*);
-
- Expression*
- lower_struct_comparison(Gogo*, Statement_inserter*);
-
- Expression*
- lower_array_comparison(Gogo*, Statement_inserter*);
-
- Expression*
- lower_compare_to_memcmp(Gogo*, Statement_inserter*);
-
- Expression*
- operand_address(Statement_inserter*, Expression*);
-
- // The binary operator to apply.
- Operator op_;
- // The left hand side operand.
- Expression* left_;
- // The right hand side operand.
- Expression* right_;
- // The type of a comparison operation.
- Type* type_;
-};
-
-// A call expression. The go statement needs to dig inside this.
-
-class Call_expression : public Expression
-{
- public:
- Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
- Location location)
- : Expression(EXPRESSION_CALL, location),
- fn_(fn), args_(args), type_(NULL), results_(NULL), tree_(NULL),
- is_varargs_(is_varargs), are_hidden_fields_ok_(false),
- varargs_are_lowered_(false), types_are_determined_(false),
- is_deferred_(false), issued_error_(false)
- { }
-
- // The function to call.
- Expression*
- fn() const
- { return this->fn_; }
-
- // The arguments.
- Expression_list*
- args()
- { return this->args_; }
-
- const Expression_list*
- args() const
- { return this->args_; }
-
- // Get the function type.
- Function_type*
- get_function_type() const;
-
- // Return the number of values this call will return.
- size_t
- result_count() const;
-
- // Return the temporary variable which holds result I. This is only
- // valid after the expression has been lowered, and is only valid
- // for calls which return multiple results.
- Temporary_statement*
- result(size_t i) const;
-
- // Return whether this is a call to the predeclared function
- // recover.
- bool
- is_recover_call() const;
-
- // Set the argument for a call to recover.
- void
- set_recover_arg(Expression*);
-
- // Whether the last argument is a varargs argument (f(a...)).
- bool
- is_varargs() const
- { return this->is_varargs_; }
-
- // Note that varargs have already been lowered.
- void
- set_varargs_are_lowered()
- { this->varargs_are_lowered_ = true; }
-
- // Note that it is OK for this call to set hidden fields when
- // passing arguments.
- void
- set_hidden_fields_are_ok()
- { this->are_hidden_fields_ok_ = true; }
-
- // Whether this call is being deferred.
- bool
- is_deferred() const
- { return this->is_deferred_; }
-
- // Note that the call is being deferred.
- void
- set_is_deferred()
- { this->is_deferred_ = true; }
-
- // We have found an error with this call expression; return true if
- // we should report it.
- bool
- issue_error();
-
- protected:
- int
- do_traverse(Traverse*);
-
- virtual Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- bool
- do_discarding_value()
- { return true; }
-
- virtual Type*
- do_type();
-
- virtual void
- do_determine_type(const Type_context*);
-
- virtual void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_call(this->fn_->copy(),
- (this->args_ == NULL
- ? NULL
- : this->args_->copy()),
- this->is_varargs_, this->location());
- }
-
- bool
- do_must_eval_in_order() const;
-
- virtual tree
- do_get_tree(Translate_context*);
-
- virtual bool
- do_is_recover_call() const;
-
- virtual void
- do_set_recover_arg(Expression*);
-
- // Let a builtin expression change the argument list.
- void
- set_args(Expression_list* args)
- { this->args_ = args; }
-
- // Let a builtin expression lower varargs.
- void
- lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
- Type* varargs_type, size_t param_count);
-
- // Let a builtin expression check whether types have been
- // determined.
- bool
- determining_types();
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- bool
- check_argument_type(int, const Type*, const Type*, Location, bool);
-
- tree
- interface_method_function(Translate_context*,
- Interface_field_reference_expression*,
- tree*);
-
- tree
- set_results(Translate_context*, tree);
-
- // The function to call.
- Expression* fn_;
- // The arguments to pass. This may be NULL if there are no
- // arguments.
- Expression_list* args_;
- // The type of the expression, to avoid recomputing it.
- Type* type_;
- // The list of temporaries which will hold the results if the
- // function returns a tuple.
- std::vector<Temporary_statement*>* results_;
- // The tree for the call, used for a call which returns a tuple.
- tree tree_;
- // True if the last argument is a varargs argument (f(a...)).
- bool is_varargs_;
- // True if this statement may pass hidden fields in the arguments.
- // This is used for generated method stubs.
- bool are_hidden_fields_ok_;
- // True if varargs have already been lowered.
- bool varargs_are_lowered_;
- // True if types have been determined.
- bool types_are_determined_;
- // True if the call is an argument to a defer statement.
- bool is_deferred_;
- // True if we reported an error about a mismatch between call
- // results and uses. This is to avoid producing multiple errors
- // when there are multiple Call_result_expressions.
- bool issued_error_;
-};
-
-// An expression which represents a pointer to a function.
-
-class Func_expression : public Expression
-{
- public:
- Func_expression(Named_object* function, Expression* closure,
- Location location)
- : Expression(EXPRESSION_FUNC_REFERENCE, location),
- function_(function), closure_(closure)
- { }
-
- // Return the object associated with the function.
- const Named_object*
- named_object() const
- { return this->function_; }
-
- // Return the closure for this function. This will return NULL if
- // the function has no closure, which is the normal case.
- Expression*
- closure()
- { return this->closure_; }
-
- // Return a tree for this function without evaluating the closure.
- tree
- get_tree_without_closure(Gogo*);
-
- protected:
- int
- do_traverse(Traverse*);
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*)
- {
- if (this->closure_ != NULL)
- this->closure_->determine_type_no_context();
- }
-
- Expression*
- do_copy()
- {
- return Expression::make_func_reference(this->function_,
- (this->closure_ == NULL
- ? NULL
- : this->closure_->copy()),
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The function itself.
- Named_object* function_;
- // A closure. This is normally NULL. For a nested function, it may
- // be a heap-allocated struct holding pointers to all the variables
- // referenced by this function and defined in enclosing functions.
- Expression* closure_;
-};
-
-// A reference to an unknown name.
-
-class Unknown_expression : public Parser_expression
-{
- public:
- Unknown_expression(Named_object* named_object, Location location)
- : Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location),
- named_object_(named_object), no_error_message_(false),
- is_composite_literal_key_(false)
- { }
-
- // The associated named object.
- Named_object*
- named_object() const
- { return this->named_object_; }
-
- // The name of the identifier which was unknown.
- const std::string&
- name() const;
-
- // Call this to indicate that we should not give an error if this
- // name is never defined. This is used to avoid knock-on errors
- // during an erroneous parse.
- void
- set_no_error_message()
- { this->no_error_message_ = true; }
-
- // Note that this expression is being used as the key in a composite
- // literal, so it may be OK if it is not resolved.
- void
- set_is_composite_literal_key()
- { this->is_composite_literal_key_ = true; }
-
- // Note that this expression should no longer be treated as a
- // composite literal key.
- void
- clear_is_composite_literal_key()
- { this->is_composite_literal_key_ = false; }
-
- protected:
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- Expression*
- do_copy()
- { return new Unknown_expression(this->named_object_, this->location()); }
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The unknown name.
- Named_object* named_object_;
- // True if we should not give errors if this is undefined. This is
- // used if there was a parse failure.
- bool no_error_message_;
- // True if this is the key in a composite literal.
- bool is_composite_literal_key_;
-};
-
-// An index expression. This is lowered to an array index, a string
-// index, or a map index.
-
-class Index_expression : public Parser_expression
-{
- public:
- Index_expression(Expression* left, Expression* start, Expression* end,
- Location location)
- : Parser_expression(EXPRESSION_INDEX, location),
- left_(left), start_(start), end_(end), is_lvalue_(false)
- { }
-
- // Record that this expression is an lvalue.
- void
- set_is_lvalue()
- { this->is_lvalue_ = true; }
-
- // Dump an index expression, i.e. an expression of the form
- // expr[expr] or expr[expr:expr], to a dump context.
- static void
- dump_index_expression(Ast_dump_context*, const Expression* expr,
- const Expression* start, const Expression* end);
-
- protected:
- int
- do_traverse(Traverse*);
-
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- Expression*
- do_copy()
- {
- return new Index_expression(this->left_->copy(), this->start_->copy(),
- (this->end_ == NULL
- ? NULL
- : this->end_->copy()),
- this->location());
- }
-
- bool
- do_must_eval_subexpressions_in_order(int* skip) const
- {
- *skip = 1;
- return true;
- }
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The expression being indexed.
- Expression* left_;
- // The first index.
- Expression* start_;
- // The second index. This is NULL for an index, non-NULL for a
- // slice.
- Expression* end_;
- // Whether this is being used as an l-value. We set this during the
- // parse because map index expressions need to know.
- bool is_lvalue_;
-};
-
-// An index into a map.
-
-class Map_index_expression : public Expression
-{
- public:
- Map_index_expression(Expression* map, Expression* index,
- Location location)
- : Expression(EXPRESSION_MAP_INDEX, location),
- map_(map), index_(index), is_lvalue_(false),
- is_in_tuple_assignment_(false)
- { }
-
- // Return the map.
- Expression*
- map()
- { return this->map_; }
-
- const Expression*
- map() const
- { return this->map_; }
-
- // Return the index.
- Expression*
- index()
- { return this->index_; }
-
- const Expression*
- index() const
- { return this->index_; }
-
- // Get the type of the map being indexed.
- Map_type*
- get_map_type() const;
-
- // Record that this map expression is an lvalue. The difference is
- // that an lvalue always inserts the key.
- void
- set_is_lvalue()
- { this->is_lvalue_ = true; }
-
- // Return whether this map expression occurs in an assignment to a
- // pair of values.
- bool
- is_in_tuple_assignment() const
- { return this->is_in_tuple_assignment_; }
-
- // Record that this map expression occurs in an assignment to a pair
- // of values.
- void
- set_is_in_tuple_assignment()
- { this->is_in_tuple_assignment_ = true; }
-
- // Return a tree for the map index. This returns a tree which
- // evaluates to a pointer to a value in the map. If INSERT is true,
- // the key will be inserted if not present, and the value pointer
- // will be zero initialized. If INSERT is false, and the key is not
- // present in the map, the pointer will be NULL.
- tree
- get_value_pointer(Translate_context*, bool insert);
-
- protected:
- int
- do_traverse(Traverse*);
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_map_index(this->map_->copy(),
- this->index_->copy(),
- this->location());
- }
-
- bool
- do_must_eval_subexpressions_in_order(int* skip) const
- {
- *skip = 1;
- return true;
- }
-
- // A map index expression is an lvalue but it is not addressable.
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The map we are looking into.
- Expression* map_;
- // The index.
- Expression* index_;
- // Whether this is an lvalue.
- bool is_lvalue_;
- // Whether this is in a tuple assignment to a pair of values.
- bool is_in_tuple_assignment_;
-};
-
-// An expression which represents a method bound to its first
-// argument.
-
-class Bound_method_expression : public Expression
-{
- public:
- Bound_method_expression(Expression* expr, Named_object* method,
- Location location)
- : Expression(EXPRESSION_BOUND_METHOD, location),
- expr_(expr), expr_type_(NULL), method_(method)
- { }
-
- // Return the object which is the first argument.
- Expression*
- first_argument()
- { return this->expr_; }
-
- // Return the implicit type of the first argument. This will be
- // non-NULL when using a method from an anonymous field without
- // using an explicit stub.
- Type*
- first_argument_type() const
- { return this->expr_type_; }
-
- // Return the method function.
- Named_object*
- method()
- { return this->method_; }
-
- // Set the implicit type of the expression.
- void
- set_first_argument_type(Type* type)
- { this->expr_type_ = type; }
-
- protected:
- int
- do_traverse(Traverse*);
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return new Bound_method_expression(this->expr_->copy(), this->method_,
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The object used to find the method. This is passed to the method
- // as the first argument.
- Expression* expr_;
- // The implicit type of the object to pass to the method. This is
- // NULL in the normal case, non-NULL when using a method from an
- // anonymous field which does not require a stub.
- Type* expr_type_;
- // The method itself.
- Named_object* method_;
-};
-
-// A reference to a field in a struct.
-
-class Field_reference_expression : public Expression
-{
- public:
- Field_reference_expression(Expression* expr, unsigned int field_index,
- Location location)
- : Expression(EXPRESSION_FIELD_REFERENCE, location),
- expr_(expr), field_index_(field_index), called_fieldtrack_(false)
- { }
-
- // Return the struct expression.
- Expression*
- expr() const
- { return this->expr_; }
-
- // Return the field index.
- unsigned int
- field_index() const
- { return this->field_index_; }
-
- // Set the struct expression. This is used when parsing.
- void
- set_struct_expression(Expression* expr)
- {
- go_assert(this->expr_ == NULL);
- this->expr_ = expr;
- }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Expression::traverse(&this->expr_, traverse); }
-
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*)
- { this->expr_->determine_type_no_context(); }
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_field_reference(this->expr_->copy(),
- this->field_index_,
- this->location());
- }
-
- bool
- do_is_addressable() const
- { return this->expr_->is_addressable(); }
-
- void
- do_address_taken(bool escapes)
- { this->expr_->address_taken(escapes); }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The expression we are looking into. This should have a type of
- // struct.
- Expression* expr_;
- // The zero-based index of the field we are retrieving.
- unsigned int field_index_;
- // Whether we have already emitted a fieldtrack call.
- bool called_fieldtrack_;
-};
-
-// A reference to a field of an interface.
-
-class Interface_field_reference_expression : public Expression
-{
- public:
- Interface_field_reference_expression(Expression* expr,
- const std::string& name,
- Location location)
- : Expression(EXPRESSION_INTERFACE_FIELD_REFERENCE, location),
- expr_(expr), name_(name)
- { }
-
- // Return the expression for the interface object.
- Expression*
- expr()
- { return this->expr_; }
-
- // Return the name of the method to call.
- const std::string&
- name() const
- { return this->name_; }
-
- // Return a tree for the pointer to the function to call, given a
- // tree for the expression.
- tree
- get_function_tree(Translate_context*, tree);
-
- // Return a tree for the first argument to pass to the interface
- // function, given a tree for the expression. This is the real
- // object associated with the interface object.
- tree
- get_underlying_object_tree(Translate_context*, tree);
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_interface_field_reference(this->expr_->copy(),
- this->name_,
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The expression for the interface object. This should have a type
- // of interface or pointer to interface.
- Expression* expr_;
- // The field we are retrieving--the name of the method.
- std::string name_;
-};
-
-// A type guard expression.
-
-class Type_guard_expression : public Expression
-{
- public:
- Type_guard_expression(Expression* expr, Type* type, Location location)
- : Expression(EXPRESSION_TYPE_GUARD, location),
- expr_(expr), type_(type)
- { }
-
- // Return the expression to convert.
- Expression*
- expr()
- { return this->expr_; }
-
- // Return the type to which to convert.
- Type*
- type()
- { return this->type_; }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- Type*
- do_type()
- { return this->type_; }
-
- void
- do_determine_type(const Type_context*)
- { this->expr_->determine_type_no_context(); }
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return new Type_guard_expression(this->expr_->copy(), this->type_,
- this->location());
- }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The expression to convert.
- Expression* expr_;
- // The type to which to convert.
- Type* type_;
-};
-
-// A receive expression.
-
-class Receive_expression : public Expression
-{
- public:
- Receive_expression(Expression* channel, Location location)
- : Expression(EXPRESSION_RECEIVE, location),
- channel_(channel)
- { }
-
- // Return the channel.
- Expression*
- channel()
- { return this->channel_; }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Expression::traverse(&this->channel_, traverse); }
-
- bool
- do_discarding_value()
- { return true; }
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*)
- { this->channel_->determine_type_no_context(); }
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_receive(this->channel_->copy(), this->location());
- }
-
- bool
- do_must_eval_in_order() const
- { return true; }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The channel from which we are receiving.
- Expression* channel_;
-};
-
-// A numeric constant. This is used both for untyped constants and
-// for constants that have a type.
-
-class Numeric_constant
-{
- public:
- Numeric_constant()
- : classification_(NC_INVALID), type_(NULL)
- { }
-
- ~Numeric_constant();
-
- Numeric_constant(const Numeric_constant&);
-
- Numeric_constant& operator=(const Numeric_constant&);
-
- // Set to an unsigned long value.
- void
- set_unsigned_long(Type*, unsigned long);
-
- // Set to an integer value.
- void
- set_int(Type*, const mpz_t);
-
- // Set to a rune value.
- void
- set_rune(Type*, const mpz_t);
-
- // Set to a floating point value.
- void
- set_float(Type*, const mpfr_t);
-
- // Set to a complex value.
- void
- set_complex(Type*, const mpfr_t, const mpfr_t);
-
- // Classifiers.
- bool
- is_int() const
- { return this->classification_ == Numeric_constant::NC_INT; }
-
- bool
- is_rune() const
- { return this->classification_ == Numeric_constant::NC_RUNE; }
-
- bool
- is_float() const
- { return this->classification_ == Numeric_constant::NC_FLOAT; }
-
- bool
- is_complex() const
- { return this->classification_ == Numeric_constant::NC_COMPLEX; }
-
- // Value retrievers. These will initialize the values as well as
- // set them. GET_INT is only valid if IS_INT returns true, and
- // likewise respectively.
- void
- get_int(mpz_t*) const;
-
- void
- get_rune(mpz_t*) const;
-
- void
- get_float(mpfr_t*) const;
-
- void
- get_complex(mpfr_t*, mpfr_t*) const;
-
- // Codes returned by to_unsigned_long.
- enum To_unsigned_long
- {
- // Value is integer and fits in unsigned long.
- NC_UL_VALID,
- // Value is not integer.
- NC_UL_NOTINT,
- // Value is integer but is negative.
- NC_UL_NEGATIVE,
- // Value is non-negative integer but does not fit in unsigned
- // long.
- NC_UL_BIG
- };
-
- // If the value can be expressed as an integer that fits in an
- // unsigned long, set *VAL and return NC_UL_VALID. Otherwise return
- // one of the other To_unsigned_long codes.
- To_unsigned_long
- to_unsigned_long(unsigned long* val) const;
-
- // If the value can be expressed as an int, return true and
- // initialize and set VAL. This will return false for a value with
- // an explicit float or complex type, even if the value is integral.
- bool
- to_int(mpz_t* val) const;
-
- // If the value can be expressed as a float, return true and
- // initialize and set VAL.
- bool
- to_float(mpfr_t* val) const;
-
- // If the value can be expressed as a complex, return true and
- // initialize and set VR and VI.
- bool
- to_complex(mpfr_t* vr, mpfr_t* vi) const;
-
- // Get the type.
- Type*
- type() const;
-
- // If the constant can be expressed in TYPE, then set the type of
- // the constant to TYPE and return true. Otherwise return false,
- // and, if ISSUE_ERROR is true, issue an error message. LOCATION is
- // the location to use for the error.
- bool
- set_type(Type* type, bool issue_error, Location location);
-
- // Return an Expression for this value.
- Expression*
- expression(Location) const;
-
- private:
- void
- clear();
-
- To_unsigned_long
- mpz_to_unsigned_long(const mpz_t ival, unsigned long *val) const;
-
- To_unsigned_long
- mpfr_to_unsigned_long(const mpfr_t fval, unsigned long *val) const;
-
- bool
- check_int_type(Integer_type*, bool, Location) const;
-
- bool
- check_float_type(Float_type*, bool, Location);
-
- bool
- check_complex_type(Complex_type*, bool, Location);
-
- // The kinds of constants.
- enum Classification
- {
- NC_INVALID,
- NC_RUNE,
- NC_INT,
- NC_FLOAT,
- NC_COMPLEX
- };
-
- // The kind of constant.
- Classification classification_;
- // The value.
- union
- {
- // If NC_INT or NC_RUNE.
- mpz_t int_val;
- // If NC_FLOAT.
- mpfr_t float_val;
- // If NC_COMPLEX.
- struct
- {
- mpfr_t real;
- mpfr_t imag;
- } complex_val;
- } u_;
- // The type if there is one. This will be NULL for an untyped
- // constant.
- Type* type_;
-};
-
-#endif // !defined(GO_EXPRESSIONS_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/go-dump.cc b/gcc-4.8.1/gcc/go/gofrontend/go-dump.cc
deleted file mode 100644
index dd5a4c3f2..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/go-dump.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// go-dump.cc -- Go frontend debug dumps.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "go-c.h"
-#include "go-dump.h"
-
-namespace {
-
-// The list of dumps.
-
-Go_dump* dumps;
-
-} // End empty namespace.
-
-// Create a new dump.
-
-Go_dump::Go_dump(const char* name)
- : next_(dumps), name_(name), is_enabled_(false)
-{
- dumps = this;
-}
-
-// Enable a dump by name.
-
-bool
-Go_dump::enable_by_name(const char* name)
-{
- bool is_all = strcmp(name, "all") == 0;
- bool found = false;
- for (Go_dump* p = dumps; p != NULL; p = p->next_)
- {
- if (is_all || strcmp(name, p->name_) == 0)
- {
- p->is_enabled_ = true;
- found = true;
- }
- }
- return found;
-}
-
-// Enable a dump. Return 1 if this is a real name, 0 if not.
-
-GO_EXTERN_C
-int
-go_enable_dump(const char* name)
-{
- return Go_dump::enable_by_name(name) ? 1 : 0;
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/go-dump.h b/gcc-4.8.1/gcc/go/gofrontend/go-dump.h
deleted file mode 100644
index 13639bc12..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/go-dump.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// go-dump.h -- Go frontend debug dumps. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_DUMP_H
-#define GO_DUMP_H
-
-// This class manages different arguments to -fgo-dump-XXX. If you
-// want to create a new dump, create a variable of this type with the
-// name to use for XXX. You can then use is_enabled to see whether
-// the -fgo-dump-XXX option was used on the command line.
-
-class Go_dump
-{
- public:
- Go_dump(const char* name);
-
- // Whether this dump was enabled.
- bool
- is_enabled() const
- { return this->is_enabled_; }
-
- // Enable a dump by name. Return true if the dump was found.
- static bool
- enable_by_name(const char*);
-
- private:
- // The next dump. These are not in any order.
- Go_dump* next_;
- // The name of this dump.
- const char* name_;
- // Whether this dump was enabled.
- bool is_enabled_;
-};
-
-#endif // !defined(GO_DUMP_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/go-linemap.h b/gcc-4.8.1/gcc/go/gofrontend/go-linemap.h
deleted file mode 100644
index ffbcbe778..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/go-linemap.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// go-linemap.h -- interface to location tracking -*- C++ -*-
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_LINEMAP_H
-#define GO_LINEMAP_H
-
-#include "go-system.h"
-
-// The backend must define a type named Location which holds
-// information about a location in a source file. The only thing the
-// frontend does with instances of Location is pass them back to the
-// backend interface. The Location type must be assignable, and it
-// must be comparable: i.e., it must support operator= and operator<.
-// The type is normally passed by value rather than by reference, and
-// it should support that efficiently. The type should be defined in
-// "go-location.h".
-
-#include "go-location.h"
-
-// The Linemap class is a pure abstract interface, plus some static
-// convenience functions. The backend must implement the interface.
-
-class Linemap
-{
- public:
- Linemap()
- {
- // Only one instance of Linemap is allowed to exist.
- go_assert(Linemap::instance_ == NULL);
- Linemap::instance_ = this;
- }
-
- virtual
- ~Linemap() { Linemap::instance_ = NULL; }
-
- // Subsequent Location values will come from the file named
- // FILE_NAME, starting at LINE_BEGIN. Normally LINE_BEGIN will be
- // 0, but it will be non-zero if the Go source has a //line comment.
- virtual void
- start_file(const char* file_name, unsigned int line_begin) = 0;
-
- // Subsequent Location values will come from the line LINE_NUMBER,
- // in the current file. LINE_SIZE is the size of the line in bytes.
- // This will normally be called for every line in a source file.
- virtual void
- start_line(unsigned int line_number, unsigned int line_size) = 0;
-
- // Get a Location representing column position COLUMN on the current
- // line in the current file.
- virtual Location
- get_location(unsigned int column) = 0;
-
- // Stop generating Location values. This will be called after all
- // input files have been read, in case any cleanup is required.
- virtual void
- stop() = 0;
-
- protected:
- // Return a special Location used for predeclared identifiers. This
- // Location should be different from that for any actual source
- // file. This location will be used for various different types,
- // functions, and objects created by the frontend.
- virtual Location
- get_predeclared_location() = 0;
-
- // Return a special Location which indicates that no actual location
- // is known. This is used for undefined objects and for errors.
- virtual Location
- get_unknown_location() = 0;
-
- // Return whether the argument is the Location returned by
- // get_predeclared_location.
- virtual bool
- is_predeclared(Location) = 0;
-
- // Return whether the argument is the Location returned by
- // get_unknown_location.
- virtual bool
- is_unknown(Location) = 0;
-
- // The single existing instance of Linemap.
- static Linemap *instance_;
-
- public:
- // Following are convenience static functions, which allow us to
- // access some virtual functions without explicitly passing around
- // an instance of Linemap.
-
- // Return the special Location used for predeclared identifiers.
- static Location
- predeclared_location()
- {
- go_assert(Linemap::instance_ != NULL);
- return Linemap::instance_->get_predeclared_location();
- }
-
- // Return the special Location used when no location is known.
- static Location
- unknown_location()
- {
- go_assert(Linemap::instance_ != NULL);
- return Linemap::instance_->get_unknown_location();
- }
-
- // Return whether the argument is the special location used for
- // predeclared identifiers.
- static bool
- is_predeclared_location(Location loc)
- {
- go_assert(Linemap::instance_ != NULL);
- return Linemap::instance_->is_predeclared(loc);
- }
-
- // Return whether the argument is the special location used when no
- // location is known.
- static bool
- is_unknown_location(Location loc)
- {
- go_assert(Linemap::instance_ != NULL);
- return Linemap::instance_->is_unknown(loc);
- }
-};
-
-// The backend interface must define this function. It should return
-// a fully implemented instance of Linemap.
-extern Linemap* go_get_linemap();
-
-#endif // !defined(GO_LINEMAP_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/go-optimize.cc b/gcc-4.8.1/gcc/go/gofrontend/go-optimize.cc
deleted file mode 100644
index 6da934f4d..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/go-optimize.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// go-optimize.cc -- Go frontend optimizer flags.
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "go-c.h"
-#include "go-optimize.h"
-
-namespace {
-
-// The list of optimizations.
-
-Go_optimize* optimizations;
-
-} // End empty namespace.
-
-// Create a new optimization.
-
-Go_optimize::Go_optimize(const char* name)
- : next_(optimizations), name_(name), is_enabled_(false)
-{
- optimizations = this;
-}
-
-// Enable an optimization by name.
-
-bool
-Go_optimize::enable_by_name(const char* name)
-{
- bool is_all = strcmp(name, "all") == 0;
- bool found = false;
- for (Go_optimize* p = optimizations; p != NULL; p = p->next_)
- {
- if (is_all || strcmp(name, p->name_) == 0)
- {
- p->is_enabled_ = true;
- found = true;
- }
- }
- return found;
-}
-
-// Enable an optimization. Return 1 if this is a real name, 0 if not.
-
-GO_EXTERN_C
-int
-go_enable_optimize(const char* name)
-{
- return Go_optimize::enable_by_name(name) ? 1 : 0;
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/go-optimize.h b/gcc-4.8.1/gcc/go/gofrontend/go-optimize.h
deleted file mode 100644
index 8638498e1..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/go-optimize.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// go-optimize.h -- Go frontend optimizer flags. -*- C++ -*-
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_OPTIMIZE_H
-#define GO_OPTIMIZE_H
-
-// This class manages different arguments to -fgo-optimize-XXX. If you
-// want to create a new optimization, create a variable of this type with the
-// name to use for XXX. You can then use is_enabled to see whether
-// the -fgo-optimize-XXX option was used on the command line.
-
-class Go_optimize
-{
- public:
- Go_optimize(const char* name);
-
- // Whether this optimizaiton was enabled.
- bool
- is_enabled() const
- { return this->is_enabled_; }
-
- // Enable an optimization by name. Return true if found.
- static bool
- enable_by_name(const char*);
-
- private:
- // The next optimize flag. These are not in any order.
- Go_optimize* next_;
- // The name of this optimization pass.
- const char* name_;
- // Whether this dump was enabled.
- bool is_enabled_;
-};
-
-#endif // !defined(GO_OPTIMIZE_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/go.cc b/gcc-4.8.1/gcc/go/gofrontend/go.cc
deleted file mode 100644
index 11692af80..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/go.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// go.cc -- Go frontend main file for gcc.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "go-c.h"
-
-#include "lex.h"
-#include "parse.h"
-#include "backend.h"
-#include "gogo.h"
-
-// The data structures we build to represent the file.
-static Gogo* gogo;
-
-// Create the main IR data structure.
-
-GO_EXTERN_C
-void
-go_create_gogo(int int_type_size, int pointer_size, const char *pkgpath,
- const char *prefix, const char *relative_import_path)
-{
- go_assert(::gogo == NULL);
- Linemap* linemap = go_get_linemap();
- ::gogo = new Gogo(go_get_backend(), linemap, int_type_size, pointer_size);
-
- if (pkgpath != NULL)
- ::gogo->set_pkgpath(pkgpath);
- else if (prefix != NULL)
- ::gogo->set_prefix(prefix);
-
- if (relative_import_path != NULL)
- ::gogo->set_relative_import_path(relative_import_path);
-
- // FIXME: This should be in the gcc dependent code.
- ::gogo->define_builtin_function_trees();
-}
-
-// Parse the input files.
-
-GO_EXTERN_C
-void
-go_parse_input_files(const char** filenames, unsigned int filename_count,
- bool only_check_syntax, bool require_return_statement)
-{
- go_assert(filename_count > 0);
-
- for (unsigned int i = 0; i < filename_count; ++i)
- {
- if (i > 0)
- ::gogo->clear_file_scope();
-
- const char* filename = filenames[i];
- FILE* file;
- if (strcmp(filename, "-") == 0)
- file = stdin;
- else
- {
- file = fopen(filename, "r");
- if (file == NULL)
- fatal_error("cannot open %s: %m", filename);
- }
-
- Lex lexer(filename, file, ::gogo->linemap());
-
- Parse parse(&lexer, ::gogo);
- parse.program();
-
- if (strcmp(filename, "-") != 0)
- fclose(file);
- }
-
- ::gogo->linemap()->stop();
-
- ::gogo->clear_file_scope();
-
- // If the global predeclared names are referenced but not defined,
- // define them now.
- ::gogo->define_global_names();
-
- // Finalize method lists and build stub methods for named types.
- ::gogo->finalize_methods();
-
- // Now that we have seen all the names, lower the parse tree into a
- // form which is easier to use.
- ::gogo->lower_parse_tree();
-
- // Write out queued up functions for hash and comparison of types.
- ::gogo->write_specific_type_functions();
-
- // Now that we have seen all the names, verify that types are
- // correct.
- ::gogo->verify_types();
-
- // Work out types of unspecified constants and variables.
- ::gogo->determine_types();
-
- // Check types and issue errors as appropriate.
- ::gogo->check_types();
-
- if (only_check_syntax)
- return;
-
- // Check that functions have return statements.
- if (require_return_statement)
- ::gogo->check_return_statements();
-
- // Export global identifiers as appropriate.
- ::gogo->do_exports();
-
- // Turn short-cut operators (&&, ||) into explicit if statements.
- ::gogo->remove_shortcuts();
-
- // Use temporary variables to force order of evaluation.
- ::gogo->order_evaluations();
-
- // Build thunks for functions which call recover.
- ::gogo->build_recover_thunks();
-
- // Convert complicated go and defer statements into simpler ones.
- ::gogo->simplify_thunk_statements();
-
- // Dump ast, use filename[0] as the base name
- ::gogo->dump_ast(filenames[0]);
-}
-
-// Write out globals.
-
-GO_EXTERN_C
-void
-go_write_globals()
-{
- return ::gogo->write_globals();
-}
-
-// Return the global IR structure. This is used by some of the
-// langhooks to pass to other code.
-
-Gogo*
-go_get_gogo()
-{
- return ::gogo;
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/gogo-tree.cc b/gcc-4.8.1/gcc/go/gofrontend/gogo-tree.cc
deleted file mode 100644
index b98404519..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/gogo-tree.cc
+++ /dev/null
@@ -1,2506 +0,0 @@
-// gogo-tree.cc -- convert Go frontend Gogo IR to gcc trees.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "toplev.h"
-#include "tree.h"
-#include "gimple.h"
-#include "tree-iterator.h"
-#include "cgraph.h"
-#include "langhooks.h"
-#include "convert.h"
-#include "output.h"
-#include "diagnostic.h"
-#include "go-c.h"
-
-#include "types.h"
-#include "expressions.h"
-#include "statements.h"
-#include "runtime.h"
-#include "backend.h"
-#include "gogo.h"
-
-// Whether we have seen any errors.
-
-bool
-saw_errors()
-{
- return errorcount != 0 || sorrycount != 0;
-}
-
-// A helper function.
-
-static inline tree
-get_identifier_from_string(const std::string& str)
-{
- return get_identifier_with_length(str.data(), str.length());
-}
-
-// Builtin functions.
-
-static std::map<std::string, tree> builtin_functions;
-
-// Define a builtin function. BCODE is the builtin function code
-// defined by builtins.def. NAME is the name of the builtin function.
-// LIBNAME is the name of the corresponding library function, and is
-// NULL if there isn't one. FNTYPE is the type of the function.
-// CONST_P is true if the function has the const attribute.
-
-static void
-define_builtin(built_in_function bcode, const char* name, const char* libname,
- tree fntype, bool const_p)
-{
- tree decl = add_builtin_function(name, fntype, bcode, BUILT_IN_NORMAL,
- libname, NULL_TREE);
- if (const_p)
- TREE_READONLY(decl) = 1;
- set_builtin_decl(bcode, decl, true);
- builtin_functions[name] = decl;
- if (libname != NULL)
- {
- decl = add_builtin_function(libname, fntype, bcode, BUILT_IN_NORMAL,
- NULL, NULL_TREE);
- if (const_p)
- TREE_READONLY(decl) = 1;
- builtin_functions[libname] = decl;
- }
-}
-
-// Create trees for implicit builtin functions.
-
-void
-Gogo::define_builtin_function_trees()
-{
- /* We need to define the fetch_and_add functions, since we use them
- for ++ and --. */
- tree t = go_type_for_size(BITS_PER_UNIT, 1);
- tree p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
- define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_1, "__sync_fetch_and_add_1", NULL,
- build_function_type_list(t, p, t, NULL_TREE), false);
-
- t = go_type_for_size(BITS_PER_UNIT * 2, 1);
- p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
- define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_2, "__sync_fetch_and_add_2", NULL,
- build_function_type_list(t, p, t, NULL_TREE), false);
-
- t = go_type_for_size(BITS_PER_UNIT * 4, 1);
- p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
- define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_4, "__sync_fetch_and_add_4", NULL,
- build_function_type_list(t, p, t, NULL_TREE), false);
-
- t = go_type_for_size(BITS_PER_UNIT * 8, 1);
- p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
- define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_8, "__sync_fetch_and_add_8", NULL,
- build_function_type_list(t, p, t, NULL_TREE), false);
-
- // We use __builtin_expect for magic import functions.
- define_builtin(BUILT_IN_EXPECT, "__builtin_expect", NULL,
- build_function_type_list(long_integer_type_node,
- long_integer_type_node,
- long_integer_type_node,
- NULL_TREE),
- true);
-
- // We use __builtin_memcmp for struct comparisons.
- define_builtin(BUILT_IN_MEMCMP, "__builtin_memcmp", "memcmp",
- build_function_type_list(integer_type_node,
- const_ptr_type_node,
- const_ptr_type_node,
- size_type_node,
- NULL_TREE),
- false);
-
- // We provide some functions for the math library.
- tree math_function_type = build_function_type_list(double_type_node,
- double_type_node,
- NULL_TREE);
- tree math_function_type_long =
- build_function_type_list(long_double_type_node, long_double_type_node,
- long_double_type_node, NULL_TREE);
- tree math_function_type_two = build_function_type_list(double_type_node,
- double_type_node,
- double_type_node,
- NULL_TREE);
- tree math_function_type_long_two =
- build_function_type_list(long_double_type_node, long_double_type_node,
- long_double_type_node, NULL_TREE);
- define_builtin(BUILT_IN_ACOS, "__builtin_acos", "acos",
- math_function_type, true);
- define_builtin(BUILT_IN_ACOSL, "__builtin_acosl", "acosl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_ASIN, "__builtin_asin", "asin",
- math_function_type, true);
- define_builtin(BUILT_IN_ASINL, "__builtin_asinl", "asinl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_ATAN, "__builtin_atan", "atan",
- math_function_type, true);
- define_builtin(BUILT_IN_ATANL, "__builtin_atanl", "atanl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_ATAN2, "__builtin_atan2", "atan2",
- math_function_type_two, true);
- define_builtin(BUILT_IN_ATAN2L, "__builtin_atan2l", "atan2l",
- math_function_type_long_two, true);
- define_builtin(BUILT_IN_CEIL, "__builtin_ceil", "ceil",
- math_function_type, true);
- define_builtin(BUILT_IN_CEILL, "__builtin_ceill", "ceill",
- math_function_type_long, true);
- define_builtin(BUILT_IN_COS, "__builtin_cos", "cos",
- math_function_type, true);
- define_builtin(BUILT_IN_COSL, "__builtin_cosl", "cosl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_EXP, "__builtin_exp", "exp",
- math_function_type, true);
- define_builtin(BUILT_IN_EXPL, "__builtin_expl", "expl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_EXPM1, "__builtin_expm1", "expm1",
- math_function_type, true);
- define_builtin(BUILT_IN_EXPM1L, "__builtin_expm1l", "expm1l",
- math_function_type_long, true);
- define_builtin(BUILT_IN_FABS, "__builtin_fabs", "fabs",
- math_function_type, true);
- define_builtin(BUILT_IN_FABSL, "__builtin_fabsl", "fabsl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_FLOOR, "__builtin_floor", "floor",
- math_function_type, true);
- define_builtin(BUILT_IN_FLOORL, "__builtin_floorl", "floorl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_FMOD, "__builtin_fmod", "fmod",
- math_function_type_two, true);
- define_builtin(BUILT_IN_FMODL, "__builtin_fmodl", "fmodl",
- math_function_type_long_two, true);
- define_builtin(BUILT_IN_LDEXP, "__builtin_ldexp", "ldexp",
- build_function_type_list(double_type_node,
- double_type_node,
- integer_type_node,
- NULL_TREE),
- true);
- define_builtin(BUILT_IN_LDEXPL, "__builtin_ldexpl", "ldexpl",
- build_function_type_list(long_double_type_node,
- long_double_type_node,
- integer_type_node,
- NULL_TREE),
- true);
- define_builtin(BUILT_IN_LOG, "__builtin_log", "log",
- math_function_type, true);
- define_builtin(BUILT_IN_LOGL, "__builtin_logl", "logl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_LOG1P, "__builtin_log1p", "log1p",
- math_function_type, true);
- define_builtin(BUILT_IN_LOG1PL, "__builtin_log1pl", "log1pl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_LOG10, "__builtin_log10", "log10",
- math_function_type, true);
- define_builtin(BUILT_IN_LOG10L, "__builtin_log10l", "log10l",
- math_function_type_long, true);
- define_builtin(BUILT_IN_LOG2, "__builtin_log2", "log2",
- math_function_type, true);
- define_builtin(BUILT_IN_LOG2L, "__builtin_log2l", "log2l",
- math_function_type_long, true);
- define_builtin(BUILT_IN_SIN, "__builtin_sin", "sin",
- math_function_type, true);
- define_builtin(BUILT_IN_SINL, "__builtin_sinl", "sinl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_SQRT, "__builtin_sqrt", "sqrt",
- math_function_type, true);
- define_builtin(BUILT_IN_SQRTL, "__builtin_sqrtl", "sqrtl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_TAN, "__builtin_tan", "tan",
- math_function_type, true);
- define_builtin(BUILT_IN_TANL, "__builtin_tanl", "tanl",
- math_function_type_long, true);
- define_builtin(BUILT_IN_TRUNC, "__builtin_trunc", "trunc",
- math_function_type, true);
- define_builtin(BUILT_IN_TRUNCL, "__builtin_truncl", "truncl",
- math_function_type_long, true);
-
- // We use __builtin_return_address in the thunk we build for
- // functions which call recover.
- define_builtin(BUILT_IN_RETURN_ADDRESS, "__builtin_return_address", NULL,
- build_function_type_list(ptr_type_node,
- unsigned_type_node,
- NULL_TREE),
- false);
-
- // The compiler uses __builtin_trap for some exception handling
- // cases.
- define_builtin(BUILT_IN_TRAP, "__builtin_trap", NULL,
- build_function_type(void_type_node, void_list_node),
- false);
-}
-
-// Get the name to use for the import control function. If there is a
-// global function or variable, then we know that that name must be
-// unique in the link, and we use it as the basis for our name.
-
-const std::string&
-Gogo::get_init_fn_name()
-{
- if (this->init_fn_name_.empty())
- {
- go_assert(this->package_ != NULL);
- if (this->is_main_package())
- {
- // Use a name which the runtime knows.
- this->init_fn_name_ = "__go_init_main";
- }
- else
- {
- std::string s = this->pkgpath_symbol();
- s.append("..import");
- this->init_fn_name_ = s;
- }
- }
-
- return this->init_fn_name_;
-}
-
-// Add statements to INIT_STMT_LIST which run the initialization
-// functions for imported packages. This is only used for the "main"
-// package.
-
-void
-Gogo::init_imports(tree* init_stmt_list)
-{
- go_assert(this->is_main_package());
-
- if (this->imported_init_fns_.empty())
- return;
-
- tree fntype = build_function_type(void_type_node, void_list_node);
-
- // We must call them in increasing priority order.
- std::vector<Import_init> v;
- for (std::set<Import_init>::const_iterator p =
- this->imported_init_fns_.begin();
- p != this->imported_init_fns_.end();
- ++p)
- v.push_back(*p);
- std::sort(v.begin(), v.end());
-
- for (std::vector<Import_init>::const_iterator p = v.begin();
- p != v.end();
- ++p)
- {
- std::string user_name = p->package_name() + ".init";
- tree decl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL,
- get_identifier_from_string(user_name),
- fntype);
- const std::string& init_name(p->init_name());
- SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(init_name));
- TREE_PUBLIC(decl) = 1;
- DECL_EXTERNAL(decl) = 1;
- append_to_statement_list(build_call_expr(decl, 0), init_stmt_list);
- }
-}
-
-// Register global variables with the garbage collector. We need to
-// register all variables which can hold a pointer value. They become
-// roots during the mark phase. We build a struct that is easy to
-// hook into a list of roots.
-
-// struct __go_gc_root_list
-// {
-// struct __go_gc_root_list* __next;
-// struct __go_gc_root
-// {
-// void* __decl;
-// size_t __size;
-// } __roots[];
-// };
-
-// The last entry in the roots array has a NULL decl field.
-
-void
-Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
- tree* init_stmt_list)
-{
- if (var_gc.empty())
- return;
-
- size_t count = var_gc.size();
-
- tree root_type = Gogo::builtin_struct(NULL, "__go_gc_root", NULL_TREE, 2,
- "__next",
- ptr_type_node,
- "__size",
- sizetype);
-
- tree index_type = build_index_type(size_int(count));
- tree array_type = build_array_type(root_type, index_type);
-
- tree root_list_type = make_node(RECORD_TYPE);
- root_list_type = Gogo::builtin_struct(NULL, "__go_gc_root_list",
- root_list_type, 2,
- "__next",
- build_pointer_type(root_list_type),
- "__roots",
- array_type);
-
- // Build an initialier for the __roots array.
-
- vec<constructor_elt, va_gc> *roots_init;
- vec_alloc(roots_init, count + 1);
-
- size_t i = 0;
- for (std::vector<Named_object*>::const_iterator p = var_gc.begin();
- p != var_gc.end();
- ++p, ++i)
- {
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(root_type);
- elt->index = field;
- Bvariable* bvar = (*p)->get_backend_variable(this, NULL);
- tree decl = var_to_tree(bvar);
- go_assert(TREE_CODE(decl) == VAR_DECL);
- elt->value = build_fold_addr_expr(decl);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- elt->index = field;
- elt->value = DECL_SIZE_UNIT(decl);
-
- elt = roots_init->quick_push(empty);
- elt->index = size_int(i);
- elt->value = build_constructor(root_type, init);
- }
-
- // The list ends with a NULL entry.
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(root_type);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- elt->index = field;
- elt->value = size_zero_node;
-
- elt = roots_init->quick_push(empty);
- elt->index = size_int(i);
- elt->value = build_constructor(root_type, init);
-
- // Build a constructor for the struct.
-
- vec<constructor_elt, va_gc> *root_list_init;
- vec_alloc(root_list_init, 2);
-
- elt = root_list_init->quick_push(empty);
- field = TYPE_FIELDS(root_list_type);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
-
- elt = root_list_init->quick_push(empty);
- field = DECL_CHAIN(field);
- elt->index = field;
- elt->value = build_constructor(array_type, roots_init);
-
- // Build a decl to register.
-
- tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
- create_tmp_var_name("gc"), root_list_type);
- DECL_EXTERNAL(decl) = 0;
- TREE_PUBLIC(decl) = 0;
- TREE_STATIC(decl) = 1;
- DECL_ARTIFICIAL(decl) = 1;
- DECL_INITIAL(decl) = build_constructor(root_list_type, root_list_init);
- rest_of_decl_compilation(decl, 1, 0);
-
- static tree register_gc_fndecl;
- tree call = Gogo::call_builtin(&register_gc_fndecl,
- Linemap::predeclared_location(),
- "__go_register_gc_roots",
- 1,
- void_type_node,
- build_pointer_type(root_list_type),
- build_fold_addr_expr(decl));
- if (call != error_mark_node)
- append_to_statement_list(call, init_stmt_list);
-}
-
-// Build the decl for the initialization function.
-
-tree
-Gogo::initialization_function_decl()
-{
- // The tedious details of building your own function. There doesn't
- // seem to be a helper function for this.
- std::string name = this->package_name() + ".init";
- tree fndecl = build_decl(this->package_->location().gcc_location(),
- FUNCTION_DECL, get_identifier_from_string(name),
- build_function_type(void_type_node,
- void_list_node));
- const std::string& asm_name(this->get_init_fn_name());
- SET_DECL_ASSEMBLER_NAME(fndecl, get_identifier_from_string(asm_name));
-
- tree resdecl = build_decl(this->package_->location().gcc_location(),
- RESULT_DECL, NULL_TREE, void_type_node);
- DECL_ARTIFICIAL(resdecl) = 1;
- DECL_CONTEXT(resdecl) = fndecl;
- DECL_RESULT(fndecl) = resdecl;
-
- TREE_STATIC(fndecl) = 1;
- TREE_USED(fndecl) = 1;
- DECL_ARTIFICIAL(fndecl) = 1;
- TREE_PUBLIC(fndecl) = 1;
-
- DECL_INITIAL(fndecl) = make_node(BLOCK);
- TREE_USED(DECL_INITIAL(fndecl)) = 1;
-
- return fndecl;
-}
-
-// Create the magic initialization function. INIT_STMT_LIST is the
-// code that it needs to run.
-
-void
-Gogo::write_initialization_function(tree fndecl, tree init_stmt_list)
-{
- // Make sure that we thought we needed an initialization function,
- // as otherwise we will not have reported it in the export data.
- go_assert(this->is_main_package() || this->need_init_fn_);
-
- if (fndecl == NULL_TREE)
- fndecl = this->initialization_function_decl();
-
- DECL_SAVED_TREE(fndecl) = init_stmt_list;
-
- if (DECL_STRUCT_FUNCTION(fndecl) == NULL)
- push_struct_function(fndecl);
- else
- push_cfun(DECL_STRUCT_FUNCTION(fndecl));
- cfun->function_start_locus = this->package_->location().gcc_location();
- cfun->function_end_locus = cfun->function_start_locus;
-
- gimplify_function_tree(fndecl);
-
- cgraph_add_new_function(fndecl, false);
-
- pop_cfun();
-}
-
-// Search for references to VAR in any statements or called functions.
-
-class Find_var : public Traverse
-{
- public:
- // A hash table we use to avoid looping. The index is the name of a
- // named object. We only look through objects defined in this
- // package.
- typedef Unordered_set(const void*) Seen_objects;
-
- Find_var(Named_object* var, Seen_objects* seen_objects)
- : Traverse(traverse_expressions),
- var_(var), seen_objects_(seen_objects), found_(false)
- { }
-
- // Whether the variable was found.
- bool
- found() const
- { return this->found_; }
-
- int
- expression(Expression**);
-
- private:
- // The variable we are looking for.
- Named_object* var_;
- // Names of objects we have already seen.
- Seen_objects* seen_objects_;
- // True if the variable was found.
- bool found_;
-};
-
-// See if EXPR refers to VAR, looking through function calls and
-// variable initializations.
-
-int
-Find_var::expression(Expression** pexpr)
-{
- Expression* e = *pexpr;
-
- Var_expression* ve = e->var_expression();
- if (ve != NULL)
- {
- Named_object* v = ve->named_object();
- if (v == this->var_)
- {
- this->found_ = true;
- return TRAVERSE_EXIT;
- }
-
- if (v->is_variable() && v->package() == NULL)
- {
- Expression* init = v->var_value()->init();
- if (init != NULL)
- {
- std::pair<Seen_objects::iterator, bool> ins =
- this->seen_objects_->insert(v);
- if (ins.second)
- {
- // This is the first time we have seen this name.
- if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- }
- }
-
- // We traverse the code of any function we see. Note that this
- // means that we will traverse the code of a function whose address
- // is taken even if it is not called.
- Func_expression* fe = e->func_expression();
- if (fe != NULL)
- {
- const Named_object* f = fe->named_object();
- if (f->is_function() && f->package() == NULL)
- {
- std::pair<Seen_objects::iterator, bool> ins =
- this->seen_objects_->insert(f);
- if (ins.second)
- {
- // This is the first time we have seen this name.
- if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- }
-
- Temporary_reference_expression* tre = e->temporary_reference_expression();
- if (tre != NULL)
- {
- Temporary_statement* ts = tre->statement();
- Expression* init = ts->init();
- if (init != NULL)
- {
- std::pair<Seen_objects::iterator, bool> ins =
- this->seen_objects_->insert(ts);
- if (ins.second)
- {
- // This is the first time we have seen this temporary
- // statement.
- if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- }
-
- return TRAVERSE_CONTINUE;
-}
-
-// Return true if EXPR, PREINIT, or DEP refers to VAR.
-
-static bool
-expression_requires(Expression* expr, Block* preinit, Named_object* dep,
- Named_object* var)
-{
- Find_var::Seen_objects seen_objects;
- Find_var find_var(var, &seen_objects);
- if (expr != NULL)
- Expression::traverse(&expr, &find_var);
- if (preinit != NULL)
- preinit->traverse(&find_var);
- if (dep != NULL)
- {
- Expression* init = dep->var_value()->init();
- if (init != NULL)
- Expression::traverse(&init, &find_var);
- if (dep->var_value()->has_pre_init())
- dep->var_value()->preinit()->traverse(&find_var);
- }
-
- return find_var.found();
-}
-
-// Sort variable initializations. If the initialization expression
-// for variable A refers directly or indirectly to the initialization
-// expression for variable B, then we must initialize B before A.
-
-class Var_init
-{
- public:
- Var_init()
- : var_(NULL), init_(NULL_TREE)
- { }
-
- Var_init(Named_object* var, tree init)
- : var_(var), init_(init)
- { }
-
- // Return the variable.
- Named_object*
- var() const
- { return this->var_; }
-
- // Return the initialization expression.
- tree
- init() const
- { return this->init_; }
-
- private:
- // The variable being initialized.
- Named_object* var_;
- // The initialization expression to run.
- tree init_;
-};
-
-typedef std::list<Var_init> Var_inits;
-
-// Sort the variable initializations. The rule we follow is that we
-// emit them in the order they appear in the array, except that if the
-// initialization expression for a variable V1 depends upon another
-// variable V2 then we initialize V1 after V2.
-
-static void
-sort_var_inits(Gogo* gogo, Var_inits* var_inits)
-{
- typedef std::pair<Named_object*, Named_object*> No_no;
- typedef std::map<No_no, bool> Cache;
- Cache cache;
-
- Var_inits ready;
- while (!var_inits->empty())
- {
- Var_inits::iterator p1 = var_inits->begin();
- Named_object* var = p1->var();
- Expression* init = var->var_value()->init();
- Block* preinit = var->var_value()->preinit();
- Named_object* dep = gogo->var_depends_on(var->var_value());
-
- // Start walking through the list to see which variables VAR
- // needs to wait for.
- Var_inits::iterator p2 = p1;
- ++p2;
-
- for (; p2 != var_inits->end(); ++p2)
- {
- Named_object* p2var = p2->var();
- No_no key(var, p2var);
- std::pair<Cache::iterator, bool> ins =
- cache.insert(std::make_pair(key, false));
- if (ins.second)
- ins.first->second = expression_requires(init, preinit, dep, p2var);
- if (ins.first->second)
- {
- // Check for cycles.
- key = std::make_pair(p2var, var);
- ins = cache.insert(std::make_pair(key, false));
- if (ins.second)
- ins.first->second =
- expression_requires(p2var->var_value()->init(),
- p2var->var_value()->preinit(),
- gogo->var_depends_on(p2var->var_value()),
- var);
- if (ins.first->second)
- {
- error_at(var->location(),
- ("initialization expressions for %qs and "
- "%qs depend upon each other"),
- var->message_name().c_str(),
- p2var->message_name().c_str());
- inform(p2->var()->location(), "%qs defined here",
- p2var->message_name().c_str());
- p2 = var_inits->end();
- }
- else
- {
- // We can't emit P1 until P2 is emitted. Move P1.
- Var_inits::iterator p3 = p2;
- ++p3;
- var_inits->splice(p3, *var_inits, p1);
- }
- break;
- }
- }
-
- if (p2 == var_inits->end())
- {
- // VAR does not depends upon any other initialization expressions.
-
- // Check for a loop of VAR on itself. We only do this if
- // INIT is not NULL and there is no dependency; when INIT is
- // NULL, it means that PREINIT sets VAR, which we will
- // interpret as a loop.
- if (init != NULL && dep == NULL
- && expression_requires(init, preinit, NULL, var))
- error_at(var->location(),
- "initialization expression for %qs depends upon itself",
- var->message_name().c_str());
- ready.splice(ready.end(), *var_inits, p1);
- }
- }
-
- // Now READY is the list in the desired initialization order.
- var_inits->swap(ready);
-}
-
-// Write out the global definitions.
-
-void
-Gogo::write_globals()
-{
- this->convert_named_types();
- this->build_interface_method_tables();
-
- Bindings* bindings = this->current_bindings();
- size_t count_definitions = bindings->size_definitions();
- size_t count = count_definitions;
-
- tree* vec = new tree[count];
-
- tree init_fndecl = NULL_TREE;
- tree init_stmt_list = NULL_TREE;
-
- if (this->is_main_package())
- this->init_imports(&init_stmt_list);
-
- // A list of variable initializations.
- Var_inits var_inits;
-
- // A list of variables which need to be registered with the garbage
- // collector.
- std::vector<Named_object*> var_gc;
- var_gc.reserve(count);
-
- tree var_init_stmt_list = NULL_TREE;
- size_t i = 0;
- for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
- p != bindings->end_definitions();
- ++p, ++i)
- {
- Named_object* no = *p;
-
- go_assert(!no->is_type_declaration() && !no->is_function_declaration());
- // There is nothing to do for a package.
- if (no->is_package())
- {
- --i;
- --count;
- continue;
- }
-
- // There is nothing to do for an object which was imported from
- // a different package into the global scope.
- if (no->package() != NULL)
- {
- --i;
- --count;
- continue;
- }
-
- // There is nothing useful we can output for constants which
- // have ideal or non-integral type.
- if (no->is_const())
- {
- Type* type = no->const_value()->type();
- if (type == NULL)
- type = no->const_value()->expr()->type();
- if (type->is_abstract() || type->integer_type() == NULL)
- {
- --i;
- --count;
- continue;
- }
- }
-
- if (!no->is_variable())
- {
- vec[i] = no->get_tree(this, NULL);
- if (vec[i] == error_mark_node)
- {
- go_assert(saw_errors());
- --i;
- --count;
- continue;
- }
- }
- else
- {
- Bvariable* var = no->get_backend_variable(this, NULL);
- vec[i] = var_to_tree(var);
- if (vec[i] == error_mark_node)
- {
- go_assert(saw_errors());
- --i;
- --count;
- continue;
- }
-
- // Check for a sink variable, which may be used to run an
- // initializer purely for its side effects.
- bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
-
- tree var_init_tree = NULL_TREE;
- if (!no->var_value()->has_pre_init())
- {
- tree init = no->var_value()->get_init_tree(this, NULL);
- if (init == error_mark_node)
- go_assert(saw_errors());
- else if (init == NULL_TREE)
- ;
- else if (TREE_CONSTANT(init))
- {
- if (expression_requires(no->var_value()->init(), NULL,
- this->var_depends_on(no->var_value()),
- no))
- error_at(no->location(),
- "initialization expression for %qs depends "
- "upon itself",
- no->message_name().c_str());
- this->backend()->global_variable_set_init(var,
- tree_to_expr(init));
- }
- else if (is_sink
- || int_size_in_bytes(TREE_TYPE(init)) == 0
- || int_size_in_bytes(TREE_TYPE(vec[i])) == 0)
- var_init_tree = init;
- else
- var_init_tree = fold_build2_loc(no->location().gcc_location(),
- MODIFY_EXPR, void_type_node,
- vec[i], init);
- }
- else
- {
- // We are going to create temporary variables which
- // means that we need an fndecl.
- if (init_fndecl == NULL_TREE)
- init_fndecl = this->initialization_function_decl();
- if (DECL_STRUCT_FUNCTION(init_fndecl) == NULL)
- push_struct_function(init_fndecl);
- else
- push_cfun(DECL_STRUCT_FUNCTION(init_fndecl));
- tree var_decl = is_sink ? NULL_TREE : vec[i];
- var_init_tree = no->var_value()->get_init_block(this, NULL,
- var_decl);
- pop_cfun();
- }
-
- if (var_init_tree != NULL_TREE && var_init_tree != error_mark_node)
- {
- if (no->var_value()->init() == NULL
- && !no->var_value()->has_pre_init())
- append_to_statement_list(var_init_tree, &var_init_stmt_list);
- else
- var_inits.push_back(Var_init(no, var_init_tree));
- }
- else if (this->var_depends_on(no->var_value()) != NULL)
- {
- // This variable is initialized from something that is
- // not in its init or preinit. This variable needs to
- // participate in dependency analysis sorting, in case
- // some other variable depends on this one.
- var_inits.push_back(Var_init(no, integer_zero_node));
- }
-
- if (!is_sink && no->var_value()->type()->has_pointer())
- var_gc.push_back(no);
- }
- }
-
- // Register global variables with the garbage collector.
- this->register_gc_vars(var_gc, &init_stmt_list);
-
- // Simple variable initializations, after all variables are
- // registered.
- append_to_statement_list(var_init_stmt_list, &init_stmt_list);
-
- // Complex variable initializations, first sorting them into a
- // workable order.
- if (!var_inits.empty())
- {
- sort_var_inits(this, &var_inits);
- for (Var_inits::const_iterator p = var_inits.begin();
- p != var_inits.end();
- ++p)
- append_to_statement_list(p->init(), &init_stmt_list);
- }
-
- // After all the variables are initialized, call the "init"
- // functions if there are any.
- for (std::vector<Named_object*>::const_iterator p =
- this->init_functions_.begin();
- p != this->init_functions_.end();
- ++p)
- {
- tree decl = (*p)->get_tree(this, NULL);
- tree call = build_call_expr(decl, 0);
- append_to_statement_list(call, &init_stmt_list);
- }
-
- // Set up a magic function to do all the initialization actions.
- // This will be called if this package is imported.
- if (init_stmt_list != NULL_TREE
- || this->need_init_fn_
- || this->is_main_package())
- this->write_initialization_function(init_fndecl, init_stmt_list);
-
- // We should not have seen any new bindings created during the
- // conversion.
- go_assert(count_definitions == this->current_bindings()->size_definitions());
-
- // Pass everything back to the middle-end.
-
- wrapup_global_declarations(vec, count);
-
- finalize_compilation_unit();
-
- check_global_declarations(vec, count);
- emit_debug_global_declarations(vec, count);
-
- delete[] vec;
-}
-
-// Get a tree for the identifier for a named object.
-
-tree
-Named_object::get_id(Gogo* gogo)
-{
- go_assert(!this->is_variable() && !this->is_result_variable());
- std::string decl_name;
- if (this->is_function_declaration()
- && !this->func_declaration_value()->asm_name().empty())
- decl_name = this->func_declaration_value()->asm_name();
- else if (this->is_type()
- && Linemap::is_predeclared_location(this->type_value()->location()))
- {
- // We don't need the package name for builtin types.
- decl_name = Gogo::unpack_hidden_name(this->name_);
- }
- else
- {
- std::string package_name;
- if (this->package_ == NULL)
- package_name = gogo->package_name();
- else
- package_name = this->package_->package_name();
-
- decl_name = package_name + '.' + Gogo::unpack_hidden_name(this->name_);
-
- Function_type* fntype;
- if (this->is_function())
- fntype = this->func_value()->type();
- else if (this->is_function_declaration())
- fntype = this->func_declaration_value()->type();
- else
- fntype = NULL;
- if (fntype != NULL && fntype->is_method())
- {
- decl_name.push_back('.');
- decl_name.append(fntype->receiver()->type()->mangled_name(gogo));
- }
- }
- if (this->is_type())
- {
- unsigned int index;
- const Named_object* in_function = this->type_value()->in_function(&index);
- if (in_function != NULL)
- {
- decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
- if (index > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", index);
- decl_name += '$';
- decl_name += buf;
- }
- }
- }
- return get_identifier_from_string(decl_name);
-}
-
-// Get a tree for a named object.
-
-tree
-Named_object::get_tree(Gogo* gogo, Named_object* function)
-{
- if (this->tree_ != NULL_TREE)
- return this->tree_;
-
- tree name;
- if (this->classification_ == NAMED_OBJECT_TYPE)
- name = NULL_TREE;
- else
- name = this->get_id(gogo);
- tree decl;
- switch (this->classification_)
- {
- case NAMED_OBJECT_CONST:
- {
- Named_constant* named_constant = this->u_.const_value;
- Translate_context subcontext(gogo, function, NULL, NULL);
- tree expr_tree = named_constant->expr()->get_tree(&subcontext);
- if (expr_tree == error_mark_node)
- decl = error_mark_node;
- else
- {
- Type* type = named_constant->type();
- if (type != NULL && !type->is_abstract())
- {
- if (type->is_error())
- expr_tree = error_mark_node;
- else
- {
- Btype* btype = type->get_backend(gogo);
- expr_tree = fold_convert(type_to_tree(btype), expr_tree);
- }
- }
- if (expr_tree == error_mark_node)
- decl = error_mark_node;
- else if (INTEGRAL_TYPE_P(TREE_TYPE(expr_tree)))
- {
- decl = build_decl(named_constant->location().gcc_location(),
- CONST_DECL, name, TREE_TYPE(expr_tree));
- DECL_INITIAL(decl) = expr_tree;
- TREE_CONSTANT(decl) = 1;
- TREE_READONLY(decl) = 1;
- }
- else
- {
- // A CONST_DECL is only for an enum constant, so we
- // shouldn't use for non-integral types. Instead we
- // just return the constant itself, rather than a
- // decl.
- decl = expr_tree;
- }
- }
- }
- break;
-
- case NAMED_OBJECT_TYPE:
- {
- Named_type* named_type = this->u_.type_value;
- tree type_tree = type_to_tree(named_type->get_backend(gogo));
- if (type_tree == error_mark_node)
- decl = error_mark_node;
- else
- {
- decl = TYPE_NAME(type_tree);
- go_assert(decl != NULL_TREE);
-
- // We need to produce a type descriptor for every named
- // type, and for a pointer to every named type, since
- // other files or packages might refer to them. We need
- // to do this even for hidden types, because they might
- // still be returned by some function. Simply calling the
- // type_descriptor method is enough to create the type
- // descriptor, even though we don't do anything with it.
- if (this->package_ == NULL)
- {
- named_type->
- type_descriptor_pointer(gogo,
- Linemap::predeclared_location());
- Type* pn = Type::make_pointer_type(named_type);
- pn->type_descriptor_pointer(gogo,
- Linemap::predeclared_location());
- }
- }
- }
- break;
-
- case NAMED_OBJECT_TYPE_DECLARATION:
- error("reference to undefined type %qs",
- this->message_name().c_str());
- return error_mark_node;
-
- case NAMED_OBJECT_VAR:
- case NAMED_OBJECT_RESULT_VAR:
- case NAMED_OBJECT_SINK:
- go_unreachable();
-
- case NAMED_OBJECT_FUNC:
- {
- Function* func = this->u_.func_value;
- decl = func->get_or_make_decl(gogo, this, name);
- if (decl != error_mark_node)
- {
- if (func->block() != NULL)
- {
- if (DECL_STRUCT_FUNCTION(decl) == NULL)
- push_struct_function(decl);
- else
- push_cfun(DECL_STRUCT_FUNCTION(decl));
-
- cfun->function_start_locus = func->location().gcc_location();
- cfun->function_end_locus =
- func->block()->end_location().gcc_location();
-
- func->build_tree(gogo, this);
-
- gimplify_function_tree(decl);
-
- cgraph_finalize_function(decl, true);
-
- pop_cfun();
- }
- }
- }
- break;
-
- case NAMED_OBJECT_ERRONEOUS:
- decl = error_mark_node;
- break;
-
- default:
- go_unreachable();
- }
-
- if (TREE_TYPE(decl) == error_mark_node)
- decl = error_mark_node;
-
- tree ret = decl;
-
- this->tree_ = ret;
-
- if (ret != error_mark_node)
- go_preserve_from_gc(ret);
-
- return ret;
-}
-
-// Get the initial value of a variable as a tree. This does not
-// consider whether the variable is in the heap--it returns the
-// initial value as though it were always stored in the stack.
-
-tree
-Variable::get_init_tree(Gogo* gogo, Named_object* function)
-{
- go_assert(this->preinit_ == NULL);
- if (this->init_ == NULL)
- {
- go_assert(!this->is_parameter_);
- if (this->is_global_ || this->is_in_heap())
- return NULL;
- Btype* btype = this->type_->get_backend(gogo);
- return expr_to_tree(gogo->backend()->zero_expression(btype));
- }
- else
- {
- Translate_context context(gogo, function, NULL, NULL);
- tree rhs_tree = this->init_->get_tree(&context);
- return Expression::convert_for_assignment(&context, this->type(),
- this->init_->type(),
- rhs_tree, this->location());
- }
-}
-
-// Get the initial value of a variable when a block is required.
-// VAR_DECL is the decl to set; it may be NULL for a sink variable.
-
-tree
-Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
-{
- go_assert(this->preinit_ != NULL);
-
- // We want to add the variable assignment to the end of the preinit
- // block. The preinit block may have a TRY_FINALLY_EXPR and a
- // TRY_CATCH_EXPR; if it does, we want to add to the end of the
- // regular statements.
-
- Translate_context context(gogo, function, NULL, NULL);
- Bblock* bblock = this->preinit_->get_backend(&context);
- tree block_tree = block_to_tree(bblock);
- if (block_tree == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(block_tree) == BIND_EXPR);
- tree statements = BIND_EXPR_BODY(block_tree);
- while (statements != NULL_TREE
- && (TREE_CODE(statements) == TRY_FINALLY_EXPR
- || TREE_CODE(statements) == TRY_CATCH_EXPR))
- statements = TREE_OPERAND(statements, 0);
-
- // It's possible to have pre-init statements without an initializer
- // if the pre-init statements set the variable.
- if (this->init_ != NULL)
- {
- tree rhs_tree = this->init_->get_tree(&context);
- if (rhs_tree == error_mark_node)
- return error_mark_node;
- if (var_decl == NULL_TREE)
- append_to_statement_list(rhs_tree, &statements);
- else
- {
- tree val = Expression::convert_for_assignment(&context, this->type(),
- this->init_->type(),
- rhs_tree,
- this->location());
- if (val == error_mark_node)
- return error_mark_node;
- tree set = fold_build2_loc(this->location().gcc_location(),
- MODIFY_EXPR, void_type_node, var_decl,
- val);
- append_to_statement_list(set, &statements);
- }
- }
-
- return block_tree;
-}
-
-// Get a tree for a function decl.
-
-tree
-Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
-{
- if (this->fndecl_ == NULL_TREE)
- {
- tree functype = type_to_tree(this->type_->get_backend(gogo));
- if (functype == error_mark_node)
- this->fndecl_ = error_mark_node;
- else
- {
- // The type of a function comes back as a pointer, but we
- // want the real function type for a function declaration.
- go_assert(POINTER_TYPE_P(functype));
- functype = TREE_TYPE(functype);
- tree decl = build_decl(this->location().gcc_location(), FUNCTION_DECL,
- id, functype);
-
- this->fndecl_ = decl;
-
- if (no->package() != NULL)
- ;
- else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
- ;
- else if (Gogo::unpack_hidden_name(no->name()) == "init"
- && !this->type_->is_method())
- ;
- else if (Gogo::unpack_hidden_name(no->name()) == "main"
- && gogo->is_main_package())
- TREE_PUBLIC(decl) = 1;
- // Methods have to be public even if they are hidden because
- // they can be pulled into type descriptors when using
- // anonymous fields.
- else if (!Gogo::is_hidden_name(no->name())
- || this->type_->is_method())
- {
- TREE_PUBLIC(decl) = 1;
- std::string asm_name = gogo->pkgpath_symbol();
- asm_name.append(1, '.');
- asm_name.append(Gogo::unpack_hidden_name(no->name()));
- if (this->type_->is_method())
- {
- asm_name.append(1, '.');
- Type* rtype = this->type_->receiver()->type();
- asm_name.append(rtype->mangled_name(gogo));
- }
- SET_DECL_ASSEMBLER_NAME(decl,
- get_identifier_from_string(asm_name));
- }
-
- // Why do we have to do this in the frontend?
- tree restype = TREE_TYPE(functype);
- tree resdecl =
- build_decl(this->location().gcc_location(), RESULT_DECL, NULL_TREE,
- restype);
- DECL_ARTIFICIAL(resdecl) = 1;
- DECL_IGNORED_P(resdecl) = 1;
- DECL_CONTEXT(resdecl) = decl;
- DECL_RESULT(decl) = resdecl;
-
- if (this->enclosing_ != NULL)
- DECL_STATIC_CHAIN(decl) = 1;
-
- // If a function calls the predeclared recover function, we
- // can't inline it, because recover behaves differently in a
- // function passed directly to defer. If this is a recover
- // thunk that we built to test whether a function can be
- // recovered, we can't inline it, because that will mess up
- // our return address comparison.
- if (this->calls_recover_ || this->is_recover_thunk_)
- DECL_UNINLINABLE(decl) = 1;
-
- // If this is a thunk created to call a function which calls
- // the predeclared recover function, we need to disable
- // stack splitting for the thunk.
- if (this->is_recover_thunk_)
- {
- tree attr = get_identifier("__no_split_stack__");
- DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
- }
-
- if (this->in_unique_section_)
- resolve_unique_section (decl, 0, 1);
-
- go_preserve_from_gc(decl);
-
- if (this->closure_var_ != NULL)
- {
- push_struct_function(decl);
-
- Bvariable* bvar = this->closure_var_->get_backend_variable(gogo,
- no);
- tree closure_decl = var_to_tree(bvar);
- if (closure_decl == error_mark_node)
- this->fndecl_ = error_mark_node;
- else
- {
- DECL_ARTIFICIAL(closure_decl) = 1;
- DECL_IGNORED_P(closure_decl) = 1;
- TREE_USED(closure_decl) = 1;
- DECL_ARG_TYPE(closure_decl) = TREE_TYPE(closure_decl);
- TREE_READONLY(closure_decl) = 1;
-
- DECL_STRUCT_FUNCTION(decl)->static_chain_decl = closure_decl;
- }
-
- pop_cfun();
- }
- }
- }
- return this->fndecl_;
-}
-
-// Get a tree for a function declaration.
-
-tree
-Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
-{
- if (this->fndecl_ == NULL_TREE)
- {
- // Let Go code use an asm declaration to pick up a builtin
- // function.
- if (!this->asm_name_.empty())
- {
- std::map<std::string, tree>::const_iterator p =
- builtin_functions.find(this->asm_name_);
- if (p != builtin_functions.end())
- {
- this->fndecl_ = p->second;
- return this->fndecl_;
- }
- }
-
- tree functype = type_to_tree(this->fntype_->get_backend(gogo));
- tree decl;
- if (functype == error_mark_node)
- decl = error_mark_node;
- else
- {
- // The type of a function comes back as a pointer, but we
- // want the real function type for a function declaration.
- go_assert(POINTER_TYPE_P(functype));
- functype = TREE_TYPE(functype);
- decl = build_decl(this->location().gcc_location(), FUNCTION_DECL, id,
- functype);
- TREE_PUBLIC(decl) = 1;
- DECL_EXTERNAL(decl) = 1;
-
- if (this->asm_name_.empty())
- {
- std::string asm_name = (no->package() == NULL
- ? gogo->pkgpath_symbol()
- : no->package()->pkgpath_symbol());
- asm_name.append(1, '.');
- asm_name.append(Gogo::unpack_hidden_name(no->name()));
- if (this->fntype_->is_method())
- {
- asm_name.append(1, '.');
- Type* rtype = this->fntype_->receiver()->type();
- asm_name.append(rtype->mangled_name(gogo));
- }
- SET_DECL_ASSEMBLER_NAME(decl,
- get_identifier_from_string(asm_name));
- }
- }
- this->fndecl_ = decl;
- go_preserve_from_gc(decl);
- }
- return this->fndecl_;
-}
-
-// We always pass the receiver to a method as a pointer. If the
-// receiver is actually declared as a non-pointer type, then we copy
-// the value into a local variable, so that it has the right type. In
-// this function we create the real PARM_DECL to use, and set
-// DEC_INITIAL of the var_decl to be the value passed in.
-
-tree
-Function::make_receiver_parm_decl(Gogo* gogo, Named_object* no, tree var_decl)
-{
- if (var_decl == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(var_decl) == VAR_DECL);
- tree val_type = TREE_TYPE(var_decl);
- bool is_in_heap = no->var_value()->is_in_heap();
- if (is_in_heap)
- {
- go_assert(POINTER_TYPE_P(val_type));
- val_type = TREE_TYPE(val_type);
- }
-
- source_location loc = DECL_SOURCE_LOCATION(var_decl);
- std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl));
- name += ".pointer";
- tree id = get_identifier_from_string(name);
- tree parm_decl = build_decl(loc, PARM_DECL, id, build_pointer_type(val_type));
- DECL_CONTEXT(parm_decl) = current_function_decl;
- DECL_ARG_TYPE(parm_decl) = TREE_TYPE(parm_decl);
-
- go_assert(DECL_INITIAL(var_decl) == NULL_TREE);
- tree init = build_fold_indirect_ref_loc(loc, parm_decl);
-
- if (is_in_heap)
- {
- tree size = TYPE_SIZE_UNIT(val_type);
- tree space = gogo->allocate_memory(no->var_value()->type(), size,
- no->location());
- space = save_expr(space);
- space = fold_convert(build_pointer_type(val_type), space);
- tree spaceref = build_fold_indirect_ref_loc(no->location().gcc_location(),
- space);
- TREE_THIS_NOTRAP(spaceref) = 1;
- tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node,
- spaceref, init);
- init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space), set, space);
- }
-
- DECL_INITIAL(var_decl) = init;
-
- return parm_decl;
-}
-
-// If we take the address of a parameter, then we need to copy it into
-// the heap. We will access it as a local variable via an
-// indirection.
-
-tree
-Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl)
-{
- if (var_decl == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(var_decl) == VAR_DECL);
- Location loc(DECL_SOURCE_LOCATION(var_decl));
-
- std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl));
- name += ".param";
- tree id = get_identifier_from_string(name);
-
- tree type = TREE_TYPE(var_decl);
- go_assert(POINTER_TYPE_P(type));
- type = TREE_TYPE(type);
-
- tree parm_decl = build_decl(loc.gcc_location(), PARM_DECL, id, type);
- DECL_CONTEXT(parm_decl) = current_function_decl;
- DECL_ARG_TYPE(parm_decl) = type;
-
- tree size = TYPE_SIZE_UNIT(type);
- tree space = gogo->allocate_memory(no->var_value()->type(), size, loc);
- space = save_expr(space);
- space = fold_convert(TREE_TYPE(var_decl), space);
- tree spaceref = build_fold_indirect_ref_loc(loc.gcc_location(), space);
- TREE_THIS_NOTRAP(spaceref) = 1;
- tree init = build2(COMPOUND_EXPR, TREE_TYPE(space),
- build2(MODIFY_EXPR, void_type_node, spaceref, parm_decl),
- space);
- DECL_INITIAL(var_decl) = init;
-
- return parm_decl;
-}
-
-// Get a tree for function code.
-
-void
-Function::build_tree(Gogo* gogo, Named_object* named_function)
-{
- tree fndecl = this->fndecl_;
- go_assert(fndecl != NULL_TREE);
-
- tree params = NULL_TREE;
- tree* pp = &params;
-
- tree declare_vars = NULL_TREE;
- for (Bindings::const_definitions_iterator p =
- this->block_->bindings()->begin_definitions();
- p != this->block_->bindings()->end_definitions();
- ++p)
- {
- if ((*p)->is_variable() && (*p)->var_value()->is_parameter())
- {
- Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
- *pp = var_to_tree(bvar);
-
- // We always pass the receiver to a method as a pointer. If
- // the receiver is declared as a non-pointer type, then we
- // copy the value into a local variable.
- if ((*p)->var_value()->is_receiver()
- && (*p)->var_value()->type()->points_to() == NULL)
- {
- tree parm_decl = this->make_receiver_parm_decl(gogo, *p, *pp);
- tree var = *pp;
- if (var != error_mark_node)
- {
- go_assert(TREE_CODE(var) == VAR_DECL);
- DECL_CHAIN(var) = declare_vars;
- declare_vars = var;
- }
- *pp = parm_decl;
- }
- else if ((*p)->var_value()->is_in_heap())
- {
- // If we take the address of a parameter, then we need
- // to copy it into the heap.
- tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp);
- tree var = *pp;
- if (var != error_mark_node)
- {
- go_assert(TREE_CODE(var) == VAR_DECL);
- DECL_CHAIN(var) = declare_vars;
- declare_vars = var;
- }
- *pp = parm_decl;
- }
-
- if (*pp != error_mark_node)
- {
- go_assert(TREE_CODE(*pp) == PARM_DECL);
- pp = &DECL_CHAIN(*pp);
- }
- }
- else if ((*p)->is_result_variable())
- {
- Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
- tree var_decl = var_to_tree(bvar);
-
- Type* type = (*p)->result_var_value()->type();
- tree init;
- if (!(*p)->result_var_value()->is_in_heap())
- {
- Btype* btype = type->get_backend(gogo);
- init = expr_to_tree(gogo->backend()->zero_expression(btype));
- }
- else
- {
- Location loc = (*p)->location();
- tree type_tree = type_to_tree(type->get_backend(gogo));
- tree space = gogo->allocate_memory(type,
- TYPE_SIZE_UNIT(type_tree),
- loc);
- tree ptr_type_tree = build_pointer_type(type_tree);
- init = fold_convert_loc(loc.gcc_location(), ptr_type_tree, space);
- }
-
- if (var_decl != error_mark_node)
- {
- go_assert(TREE_CODE(var_decl) == VAR_DECL);
- DECL_INITIAL(var_decl) = init;
- DECL_CHAIN(var_decl) = declare_vars;
- declare_vars = var_decl;
- }
- }
- }
- *pp = NULL_TREE;
-
- DECL_ARGUMENTS(fndecl) = params;
-
- if (this->block_ != NULL)
- {
- go_assert(DECL_INITIAL(fndecl) == NULL_TREE);
-
- // Declare variables if necessary.
- tree bind = NULL_TREE;
- tree defer_init = NULL_TREE;
- if (declare_vars != NULL_TREE || this->defer_stack_ != NULL)
- {
- tree block = make_node(BLOCK);
- BLOCK_SUPERCONTEXT(block) = fndecl;
- DECL_INITIAL(fndecl) = block;
- BLOCK_VARS(block) = declare_vars;
- TREE_USED(block) = 1;
-
- bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block),
- NULL_TREE, block);
- TREE_SIDE_EFFECTS(bind) = 1;
-
- if (this->defer_stack_ != NULL)
- {
- Translate_context dcontext(gogo, named_function, this->block_,
- tree_to_block(bind));
- Bstatement* bdi = this->defer_stack_->get_backend(&dcontext);
- defer_init = stat_to_tree(bdi);
- }
- }
-
- // Build the trees for all the statements in the function.
- Translate_context context(gogo, named_function, NULL, NULL);
- Bblock* bblock = this->block_->get_backend(&context);
- tree code = block_to_tree(bblock);
-
- tree init = NULL_TREE;
- tree except = NULL_TREE;
- tree fini = NULL_TREE;
-
- // Initialize variables if necessary.
- for (tree v = declare_vars; v != NULL_TREE; v = DECL_CHAIN(v))
- {
- tree dv = build1(DECL_EXPR, void_type_node, v);
- SET_EXPR_LOCATION(dv, DECL_SOURCE_LOCATION(v));
- append_to_statement_list(dv, &init);
- }
-
- // If we have a defer stack, initialize it at the start of a
- // function.
- if (defer_init != NULL_TREE && defer_init != error_mark_node)
- {
- SET_EXPR_LOCATION(defer_init,
- this->block_->start_location().gcc_location());
- append_to_statement_list(defer_init, &init);
-
- // Clean up the defer stack when we leave the function.
- this->build_defer_wrapper(gogo, named_function, &except, &fini);
- }
-
- if (code != NULL_TREE && code != error_mark_node)
- {
- if (init != NULL_TREE)
- code = build2(COMPOUND_EXPR, void_type_node, init, code);
- if (except != NULL_TREE)
- code = build2(TRY_CATCH_EXPR, void_type_node, code,
- build2(CATCH_EXPR, void_type_node, NULL, except));
- if (fini != NULL_TREE)
- code = build2(TRY_FINALLY_EXPR, void_type_node, code, fini);
- }
-
- // Stick the code into the block we built for the receiver, if
- // we built on.
- if (bind != NULL_TREE && code != NULL_TREE && code != error_mark_node)
- {
- BIND_EXPR_BODY(bind) = code;
- code = bind;
- }
-
- DECL_SAVED_TREE(fndecl) = code;
- }
-}
-
-// Build the wrappers around function code needed if the function has
-// any defer statements. This sets *EXCEPT to an exception handler
-// and *FINI to a finally handler.
-
-void
-Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
- tree *except, tree *fini)
-{
- Location end_loc = this->block_->end_location();
-
- // Add an exception handler. This is used if a panic occurs. Its
- // purpose is to stop the stack unwinding if a deferred function
- // calls recover. There are more details in
- // libgo/runtime/go-unwind.c.
-
- tree stmt_list = NULL_TREE;
-
- Expression* call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1,
- this->defer_stack(end_loc));
- Translate_context context(gogo, named_function, NULL, NULL);
- tree call_tree = call->get_tree(&context);
- if (call_tree != error_mark_node)
- append_to_statement_list(call_tree, &stmt_list);
-
- tree retval = this->return_value(gogo, named_function, end_loc, &stmt_list);
- tree set;
- if (retval == NULL_TREE)
- set = NULL_TREE;
- else
- set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
- DECL_RESULT(this->fndecl_), retval);
- tree ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR,
- void_type_node, set);
- append_to_statement_list(ret_stmt, &stmt_list);
-
- go_assert(*except == NULL_TREE);
- *except = stmt_list;
-
- // Add some finally code to run the defer functions. This is used
- // both in the normal case, when no panic occurs, and also if a
- // panic occurs to run any further defer functions. Of course, it
- // is possible for a defer function to call panic which should be
- // caught by another defer function. To handle that we use a loop.
- // finish:
- // try { __go_undefer(); } catch { __go_check_defer(); goto finish; }
- // if (return values are named) return named_vals;
-
- stmt_list = NULL;
-
- tree label = create_artificial_label(end_loc.gcc_location());
- tree define_label = fold_build1_loc(end_loc.gcc_location(), LABEL_EXPR,
- void_type_node, label);
- append_to_statement_list(define_label, &stmt_list);
-
- call = Runtime::make_call(Runtime::UNDEFER, end_loc, 1,
- this->defer_stack(end_loc));
- tree undefer = call->get_tree(&context);
-
- call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1,
- this->defer_stack(end_loc));
- tree defer = call->get_tree(&context);
-
- if (undefer == error_mark_node || defer == error_mark_node)
- return;
-
- tree jump = fold_build1_loc(end_loc.gcc_location(), GOTO_EXPR, void_type_node,
- label);
- tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer, jump);
- catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body);
- tree try_catch = build2(TRY_CATCH_EXPR, void_type_node, undefer, catch_body);
-
- append_to_statement_list(try_catch, &stmt_list);
-
- if (this->type_->results() != NULL
- && !this->type_->results()->empty()
- && !this->type_->results()->front().name().empty())
- {
- // If the result variables are named, and we are returning from
- // this function rather than panicing through it, we need to
- // return them again, because they might have been changed by a
- // defer function. The runtime routines set the defer_stack
- // variable to true if we are returning from this function.
- retval = this->return_value(gogo, named_function, end_loc,
- &stmt_list);
- set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
- DECL_RESULT(this->fndecl_), retval);
- ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR,
- void_type_node, set);
-
- Expression* ref =
- Expression::make_temporary_reference(this->defer_stack_, end_loc);
- tree tref = ref->get_tree(&context);
- tree s = build3_loc(end_loc.gcc_location(), COND_EXPR, void_type_node,
- tref, ret_stmt, NULL_TREE);
-
- append_to_statement_list(s, &stmt_list);
-
- }
-
- go_assert(*fini == NULL_TREE);
- *fini = stmt_list;
-}
-
-// Return the value to assign to DECL_RESULT(this->fndecl_). This may
-// also add statements to STMT_LIST, which need to be executed before
-// the assignment. This is used for a return statement with no
-// explicit values.
-
-tree
-Function::return_value(Gogo* gogo, Named_object* named_function,
- Location location, tree* stmt_list) const
-{
- const Typed_identifier_list* results = this->type_->results();
- if (results == NULL || results->empty())
- return NULL_TREE;
-
- go_assert(this->results_ != NULL);
- if (this->results_->size() != results->size())
- {
- go_assert(saw_errors());
- return error_mark_node;
- }
-
- tree retval;
- if (results->size() == 1)
- {
- Bvariable* bvar =
- this->results_->front()->get_backend_variable(gogo,
- named_function);
- tree ret = var_to_tree(bvar);
- if (this->results_->front()->result_var_value()->is_in_heap())
- ret = build_fold_indirect_ref_loc(location.gcc_location(), ret);
- return ret;
- }
- else
- {
- tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_));
- retval = create_tmp_var(rettype, "RESULT");
- tree field = TYPE_FIELDS(rettype);
- int index = 0;
- for (Typed_identifier_list::const_iterator pr = results->begin();
- pr != results->end();
- ++pr, ++index, field = DECL_CHAIN(field))
- {
- go_assert(field != NULL);
- Named_object* no = (*this->results_)[index];
- Bvariable* bvar = no->get_backend_variable(gogo, named_function);
- tree val = var_to_tree(bvar);
- if (no->result_var_value()->is_in_heap())
- val = build_fold_indirect_ref_loc(location.gcc_location(), val);
- tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR,
- void_type_node,
- build3(COMPONENT_REF, TREE_TYPE(field),
- retval, field, NULL_TREE),
- val);
- append_to_statement_list(set, stmt_list);
- }
- return retval;
- }
-}
-
-// Return the integer type to use for a size.
-
-GO_EXTERN_C
-tree
-go_type_for_size(unsigned int bits, int unsignedp)
-{
- const char* name;
- switch (bits)
- {
- case 8:
- name = unsignedp ? "uint8" : "int8";
- break;
- case 16:
- name = unsignedp ? "uint16" : "int16";
- break;
- case 32:
- name = unsignedp ? "uint32" : "int32";
- break;
- case 64:
- name = unsignedp ? "uint64" : "int64";
- break;
- default:
- if (bits == POINTER_SIZE && unsignedp)
- name = "uintptr";
- else
- return NULL_TREE;
- }
- Type* type = Type::lookup_integer_type(name);
- return type_to_tree(type->get_backend(go_get_gogo()));
-}
-
-// Return the type to use for a mode.
-
-GO_EXTERN_C
-tree
-go_type_for_mode(enum machine_mode mode, int unsignedp)
-{
- // FIXME: This static_cast should be in machmode.h.
- enum mode_class mc = static_cast<enum mode_class>(GET_MODE_CLASS(mode));
- if (mc == MODE_INT)
- return go_type_for_size(GET_MODE_BITSIZE(mode), unsignedp);
- else if (mc == MODE_FLOAT)
- {
- Type* type;
- switch (GET_MODE_BITSIZE (mode))
- {
- case 32:
- type = Type::lookup_float_type("float32");
- break;
- case 64:
- type = Type::lookup_float_type("float64");
- break;
- default:
- // We have to check for long double in order to support
- // i386 excess precision.
- if (mode == TYPE_MODE(long_double_type_node))
- return long_double_type_node;
- return NULL_TREE;
- }
- return type_to_tree(type->get_backend(go_get_gogo()));
- }
- else if (mc == MODE_COMPLEX_FLOAT)
- {
- Type *type;
- switch (GET_MODE_BITSIZE (mode))
- {
- case 64:
- type = Type::lookup_complex_type("complex64");
- break;
- case 128:
- type = Type::lookup_complex_type("complex128");
- break;
- default:
- // We have to check for long double in order to support
- // i386 excess precision.
- if (mode == TYPE_MODE(complex_long_double_type_node))
- return complex_long_double_type_node;
- return NULL_TREE;
- }
- return type_to_tree(type->get_backend(go_get_gogo()));
- }
- else
- return NULL_TREE;
-}
-
-// Return a tree which allocates SIZE bytes which will holds value of
-// type TYPE.
-
-tree
-Gogo::allocate_memory(Type* type, tree size, Location location)
-{
- // If the package imports unsafe, then it may play games with
- // pointers that look like integers.
- if (this->imported_unsafe_ || type->has_pointer())
- {
- static tree new_fndecl;
- return Gogo::call_builtin(&new_fndecl,
- location,
- "__go_new",
- 1,
- ptr_type_node,
- sizetype,
- size);
- }
- else
- {
- static tree new_nopointers_fndecl;
- return Gogo::call_builtin(&new_nopointers_fndecl,
- location,
- "__go_new_nopointers",
- 1,
- ptr_type_node,
- sizetype,
- size);
- }
-}
-
-// Build a builtin struct with a list of fields. The name is
-// STRUCT_NAME. STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE
-// node; this exists so that the struct can have fields which point to
-// itself. If PTYPE is not NULL, store the result in *PTYPE. There
-// are NFIELDS fields. Each field is a name (a const char*) followed
-// by a type (a tree).
-
-tree
-Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type,
- int nfields, ...)
-{
- if (ptype != NULL && *ptype != NULL_TREE)
- return *ptype;
-
- va_list ap;
- va_start(ap, nfields);
-
- tree fields = NULL_TREE;
- for (int i = 0; i < nfields; ++i)
- {
- const char* field_name = va_arg(ap, const char*);
- tree type = va_arg(ap, tree);
- if (type == error_mark_node)
- {
- if (ptype != NULL)
- *ptype = error_mark_node;
- return error_mark_node;
- }
- tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL,
- get_identifier(field_name), type);
- DECL_CHAIN(field) = fields;
- fields = field;
- }
-
- va_end(ap);
-
- if (struct_type == NULL_TREE)
- struct_type = make_node(RECORD_TYPE);
- finish_builtin_struct(struct_type, struct_name, fields, NULL_TREE);
-
- if (ptype != NULL)
- {
- go_preserve_from_gc(struct_type);
- *ptype = struct_type;
- }
-
- return struct_type;
-}
-
-// Return a type to use for pointer to const char for a string.
-
-tree
-Gogo::const_char_pointer_type_tree()
-{
- static tree type;
- if (type == NULL_TREE)
- {
- tree const_char_type = build_qualified_type(unsigned_char_type_node,
- TYPE_QUAL_CONST);
- type = build_pointer_type(const_char_type);
- go_preserve_from_gc(type);
- }
- return type;
-}
-
-// Return a tree for a string constant.
-
-tree
-Gogo::string_constant_tree(const std::string& val)
-{
- tree index_type = build_index_type(size_int(val.length()));
- tree const_char_type = build_qualified_type(unsigned_char_type_node,
- TYPE_QUAL_CONST);
- tree string_type = build_array_type(const_char_type, index_type);
- string_type = build_variant_type_copy(string_type);
- TYPE_STRING_FLAG(string_type) = 1;
- tree string_val = build_string(val.length(), val.data());
- TREE_TYPE(string_val) = string_type;
- return string_val;
-}
-
-// Return a tree for a Go string constant.
-
-tree
-Gogo::go_string_constant_tree(const std::string& val)
-{
- tree string_type = type_to_tree(Type::make_string_type()->get_backend(this));
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(string_type);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__data") == 0);
- elt->index = field;
- tree str = Gogo::string_constant_tree(val);
- elt->value = fold_convert(TREE_TYPE(field),
- build_fold_addr_expr(str));
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__length") == 0);
- elt->index = field;
- elt->value = build_int_cst_type(TREE_TYPE(field), val.length());
-
- tree constructor = build_constructor(string_type, init);
- TREE_READONLY(constructor) = 1;
- TREE_CONSTANT(constructor) = 1;
-
- return constructor;
-}
-
-// Return a tree for a pointer to a Go string constant. This is only
-// used for type descriptors, so we return a pointer to a constant
-// decl.
-
-tree
-Gogo::ptr_go_string_constant_tree(const std::string& val)
-{
- tree pval = this->go_string_constant_tree(val);
-
- tree decl = build_decl(UNKNOWN_LOCATION, VAR_DECL,
- create_tmp_var_name("SP"), TREE_TYPE(pval));
- DECL_EXTERNAL(decl) = 0;
- TREE_PUBLIC(decl) = 0;
- TREE_USED(decl) = 1;
- TREE_READONLY(decl) = 1;
- TREE_CONSTANT(decl) = 1;
- TREE_STATIC(decl) = 1;
- DECL_ARTIFICIAL(decl) = 1;
- DECL_INITIAL(decl) = pval;
- rest_of_decl_compilation(decl, 1, 0);
-
- return build_fold_addr_expr(decl);
-}
-
-// Build a constructor for a slice. SLICE_TYPE_TREE is the type of
-// the slice. VALUES is the value pointer and COUNT is the number of
-// entries. If CAPACITY is not NULL, it is the capacity; otherwise
-// the capacity and the count are the same.
-
-tree
-Gogo::slice_constructor(tree slice_type_tree, tree values, tree count,
- tree capacity)
-{
- go_assert(TREE_CODE(slice_type_tree) == RECORD_TYPE);
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 3);
-
- tree field = TYPE_FIELDS(slice_type_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- elt->index = field;
- go_assert(TYPE_MAIN_VARIANT(TREE_TYPE(field))
- == TYPE_MAIN_VARIANT(TREE_TYPE(values)));
- elt->value = values;
-
- count = fold_convert(sizetype, count);
- if (capacity == NULL_TREE)
- {
- count = save_expr(count);
- capacity = count;
- }
-
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
- elt = init->quick_push(empty);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), count);
-
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
- elt = init->quick_push(empty);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), capacity);
-
- return build_constructor(slice_type_tree, init);
-}
-
-// Build an interface method table for a type: a list of function
-// pointers, one for each interface method. This is used for
-// interfaces.
-
-tree
-Gogo::interface_method_table_for_type(const Interface_type* interface,
- Type* type, bool is_pointer)
-{
- const Typed_identifier_list* interface_methods = interface->methods();
- go_assert(!interface_methods->empty());
-
- std::string mangled_name = ((is_pointer ? "__go_pimt__" : "__go_imt_")
- + interface->mangled_name(this)
- + "__"
- + type->mangled_name(this));
-
- tree id = get_identifier_from_string(mangled_name);
-
- // See whether this interface has any hidden methods.
- bool has_hidden_methods = false;
- for (Typed_identifier_list::const_iterator p = interface_methods->begin();
- p != interface_methods->end();
- ++p)
- {
- if (Gogo::is_hidden_name(p->name()))
- {
- has_hidden_methods = true;
- break;
- }
- }
-
- // We already know that the named type is convertible to the
- // interface. If the interface has hidden methods, and the named
- // type is defined in a different package, then the interface
- // conversion table will be defined by that other package.
- if (has_hidden_methods
- && type->named_type() != NULL
- && type->named_type()->named_object()->package() != NULL)
- {
- tree array_type = build_array_type(const_ptr_type_node, NULL);
- tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type);
- TREE_READONLY(decl) = 1;
- TREE_CONSTANT(decl) = 1;
- TREE_PUBLIC(decl) = 1;
- DECL_EXTERNAL(decl) = 1;
- go_preserve_from_gc(decl);
- return decl;
- }
-
- size_t count = interface_methods->size();
- vec<constructor_elt, va_gc> *pointers;
- vec_alloc(pointers, count + 1);
-
- // The first element is the type descriptor.
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = pointers->quick_push(empty);
- elt->index = size_zero_node;
- Type* td_type;
- if (!is_pointer)
- td_type = type;
- else
- td_type = Type::make_pointer_type(type);
- tree tdp = td_type->type_descriptor_pointer(this,
- Linemap::predeclared_location());
- elt->value = fold_convert(const_ptr_type_node, tdp);
-
- Named_type* nt = type->named_type();
- Struct_type* st = type->struct_type();
- go_assert(nt != NULL || st != NULL);
- size_t i = 1;
- for (Typed_identifier_list::const_iterator p = interface_methods->begin();
- p != interface_methods->end();
- ++p, ++i)
- {
- bool is_ambiguous;
- Method* m;
- if (nt != NULL)
- m = nt->method_function(p->name(), &is_ambiguous);
- else
- m = st->method_function(p->name(), &is_ambiguous);
- go_assert(m != NULL);
-
- Named_object* no = m->named_object();
-
- tree fnid = no->get_id(this);
-
- tree fndecl;
- if (no->is_function())
- fndecl = no->func_value()->get_or_make_decl(this, no, fnid);
- else if (no->is_function_declaration())
- fndecl = no->func_declaration_value()->get_or_make_decl(this, no,
- fnid);
- else
- go_unreachable();
- fndecl = build_fold_addr_expr(fndecl);
-
- elt = pointers->quick_push(empty);
- elt->index = size_int(i);
- elt->value = fold_convert(const_ptr_type_node, fndecl);
- }
- go_assert(i == count + 1);
-
- tree array_type = build_array_type(const_ptr_type_node,
- build_index_type(size_int(count)));
- tree constructor = build_constructor(array_type, pointers);
-
- tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type);
- TREE_STATIC(decl) = 1;
- TREE_USED(decl) = 1;
- TREE_READONLY(decl) = 1;
- TREE_CONSTANT(decl) = 1;
- DECL_INITIAL(decl) = constructor;
-
- // If the interface type has hidden methods, then this is the only
- // definition of the table. Otherwise it is a comdat table which
- // may be defined in multiple packages.
- if (has_hidden_methods)
- TREE_PUBLIC(decl) = 1;
- else
- {
- make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
- resolve_unique_section(decl, 1, 0);
- }
-
- rest_of_decl_compilation(decl, 1, 0);
-
- go_preserve_from_gc(decl);
-
- return decl;
-}
-
-// Mark a function as a builtin library function.
-
-void
-Gogo::mark_fndecl_as_builtin_library(tree fndecl)
-{
- DECL_EXTERNAL(fndecl) = 1;
- TREE_PUBLIC(fndecl) = 1;
- DECL_ARTIFICIAL(fndecl) = 1;
- TREE_NOTHROW(fndecl) = 1;
- DECL_VISIBILITY(fndecl) = VISIBILITY_DEFAULT;
- DECL_VISIBILITY_SPECIFIED(fndecl) = 1;
-}
-
-// Build a call to a builtin function.
-
-tree
-Gogo::call_builtin(tree* pdecl, Location location, const char* name,
- int nargs, tree rettype, ...)
-{
- if (rettype == error_mark_node)
- return error_mark_node;
-
- tree* types = new tree[nargs];
- tree* args = new tree[nargs];
-
- va_list ap;
- va_start(ap, rettype);
- for (int i = 0; i < nargs; ++i)
- {
- types[i] = va_arg(ap, tree);
- args[i] = va_arg(ap, tree);
- if (types[i] == error_mark_node || args[i] == error_mark_node)
- {
- delete[] types;
- delete[] args;
- return error_mark_node;
- }
- }
- va_end(ap);
-
- if (*pdecl == NULL_TREE)
- {
- tree fnid = get_identifier(name);
-
- tree argtypes = NULL_TREE;
- tree* pp = &argtypes;
- for (int i = 0; i < nargs; ++i)
- {
- *pp = tree_cons(NULL_TREE, types[i], NULL_TREE);
- pp = &TREE_CHAIN(*pp);
- }
- *pp = void_list_node;
-
- tree fntype = build_function_type(rettype, argtypes);
-
- *pdecl = build_decl(BUILTINS_LOCATION, FUNCTION_DECL, fnid, fntype);
- Gogo::mark_fndecl_as_builtin_library(*pdecl);
- go_preserve_from_gc(*pdecl);
- }
-
- tree fnptr = build_fold_addr_expr(*pdecl);
- if (CAN_HAVE_LOCATION_P(fnptr))
- SET_EXPR_LOCATION(fnptr, location.gcc_location());
-
- tree ret = build_call_array(rettype, fnptr, nargs, args);
- SET_EXPR_LOCATION(ret, location.gcc_location());
-
- delete[] types;
- delete[] args;
-
- return ret;
-}
-
-// Build a call to the runtime error function.
-
-tree
-Gogo::runtime_error(int code, Location location)
-{
- Type* int32_type = Type::lookup_integer_type("int32");
- tree int32_type_tree = type_to_tree(int32_type->get_backend(this));
-
- static tree runtime_error_fndecl;
- tree ret = Gogo::call_builtin(&runtime_error_fndecl,
- location,
- "__go_runtime_error",
- 1,
- void_type_node,
- int32_type_tree,
- build_int_cst(int32_type_tree, 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;
- return ret;
-}
-
-// Return a tree for receiving a value of type TYPE_TREE on CHANNEL.
-// TYPE_DESCRIPTOR_TREE is the channel's type descriptor. This does a
-// blocking receive and returns the value read from the channel.
-
-tree
-Gogo::receive_from_channel(tree type_tree, tree type_descriptor_tree,
- tree channel, Location location)
-{
- if (type_tree == error_mark_node || channel == error_mark_node)
- return error_mark_node;
-
- if (int_size_in_bytes(type_tree) <= 8
- && !AGGREGATE_TYPE_P(type_tree)
- && !FLOAT_TYPE_P(type_tree))
- {
- static tree receive_small_fndecl;
- tree call = Gogo::call_builtin(&receive_small_fndecl,
- location,
- "__go_receive_small",
- 2,
- uint64_type_node,
- TREE_TYPE(type_descriptor_tree),
- type_descriptor_tree,
- ptr_type_node,
- channel);
- 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;
- int bitsize = GET_MODE_BITSIZE(TYPE_MODE(type_tree));
- tree int_type_tree = go_type_for_size(bitsize, 1);
- return fold_convert_loc(location.gcc_location(), type_tree,
- fold_convert_loc(location.gcc_location(),
- int_type_tree, call));
- }
- else
- {
- tree tmp = create_tmp_var(type_tree, get_name(type_tree));
- DECL_IGNORED_P(tmp) = 0;
- TREE_ADDRESSABLE(tmp) = 1;
- tree make_tmp = build1(DECL_EXPR, void_type_node, tmp);
- SET_EXPR_LOCATION(make_tmp, location.gcc_location());
- tree tmpaddr = build_fold_addr_expr(tmp);
- tmpaddr = fold_convert(ptr_type_node, tmpaddr);
- static tree receive_big_fndecl;
- tree call = Gogo::call_builtin(&receive_big_fndecl,
- location,
- "__go_receive_big",
- 3,
- void_type_node,
- TREE_TYPE(type_descriptor_tree),
- type_descriptor_tree,
- ptr_type_node,
- channel,
- ptr_type_node,
- tmpaddr);
- 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;
- return build2(COMPOUND_EXPR, type_tree, make_tmp,
- build2(COMPOUND_EXPR, type_tree, call, tmp));
- }
-}
-
-// Return the type of a function trampoline. This is like
-// get_trampoline_type in tree-nested.c.
-
-tree
-Gogo::trampoline_type_tree()
-{
- static tree type_tree;
- if (type_tree == NULL_TREE)
- {
- unsigned int size;
- unsigned int align;
- go_trampoline_info(&size, &align);
- tree t = build_index_type(build_int_cst(integer_type_node, size - 1));
- t = build_array_type(char_type_node, t);
-
- type_tree = Gogo::builtin_struct(NULL, "__go_trampoline", NULL_TREE, 1,
- "__data", t);
- t = TYPE_FIELDS(type_tree);
- DECL_ALIGN(t) = align;
- DECL_USER_ALIGN(t) = 1;
-
- go_preserve_from_gc(type_tree);
- }
- return type_tree;
-}
-
-// Make a trampoline which calls FNADDR passing CLOSURE.
-
-tree
-Gogo::make_trampoline(tree fnaddr, tree closure, Location location)
-{
- tree trampoline_type = Gogo::trampoline_type_tree();
- tree trampoline_size = TYPE_SIZE_UNIT(trampoline_type);
-
- closure = save_expr(closure);
-
- // We allocate the trampoline using a special function which will
- // mark it as executable.
- static tree trampoline_fndecl;
- tree x = Gogo::call_builtin(&trampoline_fndecl,
- location,
- "__go_allocate_trampoline",
- 2,
- ptr_type_node,
- size_type_node,
- trampoline_size,
- ptr_type_node,
- fold_convert_loc(location.gcc_location(),
- ptr_type_node, closure));
- if (x == error_mark_node)
- return error_mark_node;
-
- x = save_expr(x);
-
- // Initialize the trampoline.
- tree calldecl = builtin_decl_implicit(BUILT_IN_INIT_HEAP_TRAMPOLINE);
- tree ini = build_call_expr(calldecl, 3, x, fnaddr, closure);
-
- // On some targets the trampoline address needs to be adjusted. For
- // example, when compiling in Thumb mode on the ARM, the address
- // needs to have the low bit set.
- x = build_call_expr(builtin_decl_explicit(BUILT_IN_ADJUST_TRAMPOLINE), 1, x);
- x = fold_convert(TREE_TYPE(fnaddr), x);
-
- return build2(COMPOUND_EXPR, TREE_TYPE(x), ini, x);
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/gogo.cc b/gcc-4.8.1/gcc/go/gofrontend/gogo.cc
deleted file mode 100644
index 80ae8d464..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/gogo.cc
+++ /dev/null
@@ -1,5572 +0,0 @@
-// gogo.cc -- Go frontend parsed representation.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "filenames.h"
-
-#include "go-c.h"
-#include "go-dump.h"
-#include "lex.h"
-#include "types.h"
-#include "statements.h"
-#include "expressions.h"
-#include "dataflow.h"
-#include "runtime.h"
-#include "import.h"
-#include "export.h"
-#include "backend.h"
-#include "gogo.h"
-
-// Class Gogo.
-
-Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
- : backend_(backend),
- linemap_(linemap),
- package_(NULL),
- functions_(),
- globals_(new Bindings(NULL)),
- file_block_names_(),
- imports_(),
- imported_unsafe_(false),
- packages_(),
- init_functions_(),
- var_deps_(),
- need_init_fn_(false),
- init_fn_name_(),
- imported_init_fns_(),
- pkgpath_(),
- pkgpath_symbol_(),
- prefix_(),
- pkgpath_set_(false),
- pkgpath_from_option_(false),
- prefix_from_option_(false),
- relative_import_path_(),
- verify_types_(),
- interface_types_(),
- specific_type_functions_(),
- specific_type_functions_are_written_(false),
- named_types_are_converted_(false)
-{
- const Location loc = Linemap::predeclared_location();
-
- Named_type* uint8_type = Type::make_integer_type("uint8", true, 8,
- RUNTIME_TYPE_KIND_UINT8);
- this->add_named_type(uint8_type);
- this->add_named_type(Type::make_integer_type("uint16", true, 16,
- RUNTIME_TYPE_KIND_UINT16));
- this->add_named_type(Type::make_integer_type("uint32", true, 32,
- RUNTIME_TYPE_KIND_UINT32));
- this->add_named_type(Type::make_integer_type("uint64", true, 64,
- RUNTIME_TYPE_KIND_UINT64));
-
- this->add_named_type(Type::make_integer_type("int8", false, 8,
- RUNTIME_TYPE_KIND_INT8));
- this->add_named_type(Type::make_integer_type("int16", false, 16,
- RUNTIME_TYPE_KIND_INT16));
- Named_type* int32_type = Type::make_integer_type("int32", false, 32,
- RUNTIME_TYPE_KIND_INT32);
- this->add_named_type(int32_type);
- this->add_named_type(Type::make_integer_type("int64", false, 64,
- RUNTIME_TYPE_KIND_INT64));
-
- this->add_named_type(Type::make_float_type("float32", 32,
- RUNTIME_TYPE_KIND_FLOAT32));
- this->add_named_type(Type::make_float_type("float64", 64,
- RUNTIME_TYPE_KIND_FLOAT64));
-
- this->add_named_type(Type::make_complex_type("complex64", 64,
- RUNTIME_TYPE_KIND_COMPLEX64));
- this->add_named_type(Type::make_complex_type("complex128", 128,
- RUNTIME_TYPE_KIND_COMPLEX128));
-
- int int_type_size = pointer_size;
- if (int_type_size < 32)
- int_type_size = 32;
- this->add_named_type(Type::make_integer_type("uint", true,
- int_type_size,
- RUNTIME_TYPE_KIND_UINT));
- Named_type* int_type = Type::make_integer_type("int", false, int_type_size,
- RUNTIME_TYPE_KIND_INT);
- this->add_named_type(int_type);
-
- this->add_named_type(Type::make_integer_type("uintptr", true,
- pointer_size,
- RUNTIME_TYPE_KIND_UINTPTR));
-
- // "byte" is an alias for "uint8".
- uint8_type->integer_type()->set_is_byte();
- Named_object* byte_type = Named_object::make_type("byte", NULL, uint8_type,
- loc);
- this->add_named_type(byte_type->type_value());
-
- // "rune" is an alias for "int32".
- int32_type->integer_type()->set_is_rune();
- Named_object* rune_type = Named_object::make_type("rune", NULL, int32_type,
- loc);
- this->add_named_type(rune_type->type_value());
-
- this->add_named_type(Type::make_named_bool_type());
-
- this->add_named_type(Type::make_named_string_type());
-
- // "error" is interface { Error() string }.
- {
- Typed_identifier_list *methods = new Typed_identifier_list;
- Typed_identifier_list *results = new Typed_identifier_list;
- results->push_back(Typed_identifier("", Type::lookup_string_type(), loc));
- Type *method_type = Type::make_function_type(NULL, NULL, results, loc);
- methods->push_back(Typed_identifier("Error", method_type, loc));
- Interface_type *error_iface = Type::make_interface_type(methods, loc);
- error_iface->finalize_methods();
- Named_type *error_type = Named_object::make_type("error", NULL, error_iface, loc)->type_value();
- this->add_named_type(error_type);
- }
-
- this->globals_->add_constant(Typed_identifier("true",
- Type::make_boolean_type(),
- loc),
- NULL,
- Expression::make_boolean(true, loc),
- 0);
- this->globals_->add_constant(Typed_identifier("false",
- Type::make_boolean_type(),
- loc),
- NULL,
- Expression::make_boolean(false, loc),
- 0);
-
- this->globals_->add_constant(Typed_identifier("nil", Type::make_nil_type(),
- loc),
- NULL,
- Expression::make_nil(loc),
- 0);
-
- Type* abstract_int_type = Type::make_abstract_integer_type();
- this->globals_->add_constant(Typed_identifier("iota", abstract_int_type,
- loc),
- NULL,
- Expression::make_iota(),
- 0);
-
- Function_type* new_type = Type::make_function_type(NULL, NULL, NULL, loc);
- new_type->set_is_varargs();
- new_type->set_is_builtin();
- this->globals_->add_function_declaration("new", NULL, new_type, loc);
-
- Function_type* make_type = Type::make_function_type(NULL, NULL, NULL, loc);
- make_type->set_is_varargs();
- make_type->set_is_builtin();
- this->globals_->add_function_declaration("make", NULL, make_type, loc);
-
- Typed_identifier_list* len_result = new Typed_identifier_list();
- len_result->push_back(Typed_identifier("", int_type, loc));
- Function_type* len_type = Type::make_function_type(NULL, NULL, len_result,
- loc);
- len_type->set_is_builtin();
- this->globals_->add_function_declaration("len", NULL, len_type, loc);
-
- Typed_identifier_list* cap_result = new Typed_identifier_list();
- cap_result->push_back(Typed_identifier("", int_type, loc));
- Function_type* cap_type = Type::make_function_type(NULL, NULL, len_result,
- loc);
- cap_type->set_is_builtin();
- this->globals_->add_function_declaration("cap", NULL, cap_type, loc);
-
- Function_type* print_type = Type::make_function_type(NULL, NULL, NULL, loc);
- print_type->set_is_varargs();
- print_type->set_is_builtin();
- this->globals_->add_function_declaration("print", NULL, print_type, loc);
-
- print_type = Type::make_function_type(NULL, NULL, NULL, loc);
- print_type->set_is_varargs();
- print_type->set_is_builtin();
- this->globals_->add_function_declaration("println", NULL, print_type, loc);
-
- Type *empty = Type::make_empty_interface_type(loc);
- Typed_identifier_list* panic_parms = new Typed_identifier_list();
- panic_parms->push_back(Typed_identifier("e", empty, loc));
- Function_type *panic_type = Type::make_function_type(NULL, panic_parms,
- NULL, loc);
- panic_type->set_is_builtin();
- this->globals_->add_function_declaration("panic", NULL, panic_type, loc);
-
- Typed_identifier_list* recover_result = new Typed_identifier_list();
- recover_result->push_back(Typed_identifier("", empty, loc));
- Function_type* recover_type = Type::make_function_type(NULL, NULL,
- recover_result,
- loc);
- recover_type->set_is_builtin();
- this->globals_->add_function_declaration("recover", NULL, recover_type, loc);
-
- Function_type* close_type = Type::make_function_type(NULL, NULL, NULL, loc);
- close_type->set_is_varargs();
- close_type->set_is_builtin();
- this->globals_->add_function_declaration("close", NULL, close_type, loc);
-
- Typed_identifier_list* copy_result = new Typed_identifier_list();
- copy_result->push_back(Typed_identifier("", int_type, loc));
- Function_type* copy_type = Type::make_function_type(NULL, NULL,
- copy_result, loc);
- copy_type->set_is_varargs();
- copy_type->set_is_builtin();
- this->globals_->add_function_declaration("copy", NULL, copy_type, loc);
-
- Function_type* append_type = Type::make_function_type(NULL, NULL, NULL, loc);
- append_type->set_is_varargs();
- append_type->set_is_builtin();
- this->globals_->add_function_declaration("append", NULL, append_type, loc);
-
- Function_type* complex_type = Type::make_function_type(NULL, NULL, NULL, loc);
- complex_type->set_is_varargs();
- complex_type->set_is_builtin();
- this->globals_->add_function_declaration("complex", NULL, complex_type, loc);
-
- Function_type* real_type = Type::make_function_type(NULL, NULL, NULL, loc);
- real_type->set_is_varargs();
- real_type->set_is_builtin();
- this->globals_->add_function_declaration("real", NULL, real_type, loc);
-
- Function_type* imag_type = Type::make_function_type(NULL, NULL, NULL, loc);
- imag_type->set_is_varargs();
- imag_type->set_is_builtin();
- this->globals_->add_function_declaration("imag", NULL, imag_type, loc);
-
- Function_type* delete_type = Type::make_function_type(NULL, NULL, NULL, loc);
- delete_type->set_is_varargs();
- delete_type->set_is_builtin();
- this->globals_->add_function_declaration("delete", NULL, delete_type, loc);
-}
-
-// Convert a pkgpath into a string suitable for a symbol. Note that
-// this transformation is convenient but imperfect. A -fgo-pkgpath
-// option of a/b_c will conflict with a -fgo-pkgpath option of a_b/c,
-// possibly leading to link time errors.
-
-std::string
-Gogo::pkgpath_for_symbol(const std::string& pkgpath)
-{
- std::string s = pkgpath;
- for (size_t i = 0; i < s.length(); ++i)
- {
- char c = s[i];
- if ((c >= 'a' && c <= 'z')
- || (c >= 'A' && c <= 'Z')
- || (c >= '0' && c <= '9')
- || c == '_'
- || c == '.'
- || c == '$')
- ;
- else
- s[i] = '_';
- }
- return s;
-}
-
-// Get the package path to use for type reflection data. This should
-// ideally be unique across the entire link.
-
-const std::string&
-Gogo::pkgpath() const
-{
- go_assert(this->pkgpath_set_);
- return this->pkgpath_;
-}
-
-// Set the package path from the -fgo-pkgpath command line option.
-
-void
-Gogo::set_pkgpath(const std::string& arg)
-{
- go_assert(!this->pkgpath_set_);
- this->pkgpath_ = arg;
- this->pkgpath_set_ = true;
- this->pkgpath_from_option_ = true;
-}
-
-// Get the package path to use for symbol names.
-
-const std::string&
-Gogo::pkgpath_symbol() const
-{
- go_assert(this->pkgpath_set_);
- return this->pkgpath_symbol_;
-}
-
-// Set the unique prefix to use to determine the package path, from
-// the -fgo-prefix command line option.
-
-void
-Gogo::set_prefix(const std::string& arg)
-{
- go_assert(!this->prefix_from_option_);
- this->prefix_ = arg;
- this->prefix_from_option_ = true;
-}
-
-// Munge name for use in an error message.
-
-std::string
-Gogo::message_name(const std::string& name)
-{
- return go_localize_identifier(Gogo::unpack_hidden_name(name).c_str());
-}
-
-// Get the package name.
-
-const std::string&
-Gogo::package_name() const
-{
- go_assert(this->package_ != NULL);
- return this->package_->package_name();
-}
-
-// Set the package name.
-
-void
-Gogo::set_package_name(const std::string& package_name,
- Location location)
-{
- if (this->package_ != NULL)
- {
- if (this->package_->package_name() != package_name)
- error_at(location, "expected package %<%s%>",
- Gogo::message_name(this->package_->package_name()).c_str());
- return;
- }
-
- // Now that we know the name of the package we are compiling, set
- // the package path to use for reflect.Type.PkgPath and global
- // symbol names.
- if (!this->pkgpath_set_)
- {
- if (!this->prefix_from_option_ && package_name == "main")
- this->pkgpath_ = package_name;
- else
- {
- if (!this->prefix_from_option_)
- this->prefix_ = "go";
- this->pkgpath_ = this->prefix_ + '.' + package_name;
- }
- this->pkgpath_set_ = true;
- }
-
- this->pkgpath_symbol_ = Gogo::pkgpath_for_symbol(this->pkgpath_);
-
- this->package_ = this->register_package(this->pkgpath_, location);
- this->package_->set_package_name(package_name, location);
-
- if (this->is_main_package())
- {
- // Declare "main" as a function which takes no parameters and
- // returns no value.
- Location uloc = Linemap::unknown_location();
- this->declare_function("main",
- Type::make_function_type (NULL, NULL, NULL, uloc),
- uloc);
- }
-}
-
-// Return whether this is the "main" package. This is not true if
-// -fgo-pkgpath or -fgo-prefix was used.
-
-bool
-Gogo::is_main_package() const
-{
- return (this->package_name() == "main"
- && !this->pkgpath_from_option_
- && !this->prefix_from_option_);
-}
-
-// Import a package.
-
-void
-Gogo::import_package(const std::string& filename,
- const std::string& local_name,
- bool is_local_name_exported,
- Location location)
-{
- if (filename.empty())
- {
- error_at(location, "import path is empty");
- return;
- }
-
- const char *pf = filename.data();
- const char *pend = pf + filename.length();
- while (pf < pend)
- {
- unsigned int c;
- int adv = Lex::fetch_char(pf, &c);
- if (adv == 0)
- {
- error_at(location, "import path contains invalid UTF-8 sequence");
- return;
- }
- if (c == '\0')
- {
- error_at(location, "import path contains NUL");
- return;
- }
- if (c < 0x20 || c == 0x7f)
- {
- error_at(location, "import path contains control character");
- return;
- }
- if (c == '\\')
- {
- error_at(location, "import path contains backslash; use slash");
- return;
- }
- if (Lex::is_unicode_space(c))
- {
- error_at(location, "import path contains space character");
- return;
- }
- if (c < 0x7f && strchr("!\"#$%&'()*,:;<=>?[]^`{|}", c) != NULL)
- {
- error_at(location, "import path contains invalid character '%c'", c);
- return;
- }
- pf += adv;
- }
-
- if (IS_ABSOLUTE_PATH(filename.c_str()))
- {
- error_at(location, "import path cannot be absolute path");
- return;
- }
-
- if (filename == "unsafe")
- {
- this->import_unsafe(local_name, is_local_name_exported, location);
- return;
- }
-
- Imports::const_iterator p = this->imports_.find(filename);
- if (p != this->imports_.end())
- {
- Package* package = p->second;
- package->set_location(location);
- package->set_is_imported();
- std::string ln = local_name;
- bool is_ln_exported = is_local_name_exported;
- if (ln.empty())
- {
- ln = package->package_name();
- go_assert(!ln.empty());
- is_ln_exported = Lex::is_exported_name(ln);
- }
- if (ln == ".")
- {
- Bindings* bindings = package->bindings();
- for (Bindings::const_declarations_iterator p =
- bindings->begin_declarations();
- p != bindings->end_declarations();
- ++p)
- this->add_named_object(p->second);
- }
- else if (ln == "_")
- package->set_uses_sink_alias();
- else
- {
- ln = this->pack_hidden_name(ln, is_ln_exported);
- this->package_->bindings()->add_package(ln, package);
- }
- return;
- }
-
- Import::Stream* stream = Import::open_package(filename, location,
- this->relative_import_path_);
- if (stream == NULL)
- {
- error_at(location, "import file %qs not found", filename.c_str());
- return;
- }
-
- Import imp(stream, location);
- imp.register_builtin_types(this);
- Package* package = imp.import(this, local_name, is_local_name_exported);
- if (package != NULL)
- {
- if (package->pkgpath() == this->pkgpath())
- error_at(location,
- ("imported package uses same package path as package "
- "being compiled (see -fgo-pkgpath option)"));
-
- this->imports_.insert(std::make_pair(filename, package));
- package->set_is_imported();
- }
-
- delete stream;
-}
-
-// Add an import control function for an imported package to the list.
-
-void
-Gogo::add_import_init_fn(const std::string& package_name,
- const std::string& init_name, int prio)
-{
- for (std::set<Import_init>::const_iterator p =
- this->imported_init_fns_.begin();
- p != this->imported_init_fns_.end();
- ++p)
- {
- if (p->init_name() == init_name)
- {
- // If a test of package P1, built as part of package P1,
- // imports package P2, and P2 imports P1 (perhaps
- // indirectly), then we will see the same import name with
- // different import priorities. That is OK, so don't give
- // an error about it.
- if (p->package_name() != package_name)
- {
- error("duplicate package initialization name %qs",
- Gogo::message_name(init_name).c_str());
- inform(UNKNOWN_LOCATION, "used by package %qs at priority %d",
- Gogo::message_name(p->package_name()).c_str(),
- p->priority());
- inform(UNKNOWN_LOCATION, " and by package %qs at priority %d",
- Gogo::message_name(package_name).c_str(), prio);
- }
- return;
- }
- }
-
- this->imported_init_fns_.insert(Import_init(package_name, init_name,
- prio));
-}
-
-// Return whether we are at the global binding level.
-
-bool
-Gogo::in_global_scope() const
-{
- return this->functions_.empty();
-}
-
-// Return the current binding contour.
-
-Bindings*
-Gogo::current_bindings()
-{
- if (!this->functions_.empty())
- return this->functions_.back().blocks.back()->bindings();
- else if (this->package_ != NULL)
- return this->package_->bindings();
- else
- return this->globals_;
-}
-
-const Bindings*
-Gogo::current_bindings() const
-{
- if (!this->functions_.empty())
- return this->functions_.back().blocks.back()->bindings();
- else if (this->package_ != NULL)
- return this->package_->bindings();
- else
- return this->globals_;
-}
-
-// Return the current block.
-
-Block*
-Gogo::current_block()
-{
- if (this->functions_.empty())
- return NULL;
- else
- return this->functions_.back().blocks.back();
-}
-
-// Look up a name in the current binding contour. If PFUNCTION is not
-// NULL, set it to the function in which the name is defined, or NULL
-// if the name is defined in global scope.
-
-Named_object*
-Gogo::lookup(const std::string& name, Named_object** pfunction) const
-{
- if (pfunction != NULL)
- *pfunction = NULL;
-
- if (Gogo::is_sink_name(name))
- return Named_object::make_sink();
-
- for (Open_functions::const_reverse_iterator p = this->functions_.rbegin();
- p != this->functions_.rend();
- ++p)
- {
- Named_object* ret = p->blocks.back()->bindings()->lookup(name);
- if (ret != NULL)
- {
- if (pfunction != NULL)
- *pfunction = p->function;
- return ret;
- }
- }
-
- if (this->package_ != NULL)
- {
- Named_object* ret = this->package_->bindings()->lookup(name);
- if (ret != NULL)
- {
- if (ret->package() != NULL)
- ret->package()->set_used();
- return ret;
- }
- }
-
- // We do not look in the global namespace. If we did, the global
- // namespace would effectively hide names which were defined in
- // package scope which we have not yet seen. Instead,
- // define_global_names is called after parsing is over to connect
- // undefined names at package scope with names defined at global
- // scope.
-
- return NULL;
-}
-
-// Look up a name in the current block, without searching enclosing
-// blocks.
-
-Named_object*
-Gogo::lookup_in_block(const std::string& name) const
-{
- go_assert(!this->functions_.empty());
- go_assert(!this->functions_.back().blocks.empty());
- return this->functions_.back().blocks.back()->bindings()->lookup_local(name);
-}
-
-// Look up a name in the global namespace.
-
-Named_object*
-Gogo::lookup_global(const char* name) const
-{
- return this->globals_->lookup(name);
-}
-
-// Add an imported package.
-
-Package*
-Gogo::add_imported_package(const std::string& real_name,
- const std::string& alias_arg,
- bool is_alias_exported,
- const std::string& pkgpath,
- Location location,
- bool* padd_to_globals)
-{
- Package* ret = this->register_package(pkgpath, location);
- ret->set_package_name(real_name, location);
-
- *padd_to_globals = false;
-
- if (alias_arg == ".")
- *padd_to_globals = true;
- else if (alias_arg == "_")
- ret->set_uses_sink_alias();
- else
- {
- std::string alias = alias_arg;
- if (alias.empty())
- {
- alias = real_name;
- is_alias_exported = Lex::is_exported_name(alias);
- }
- alias = this->pack_hidden_name(alias, is_alias_exported);
- Named_object* no = this->package_->bindings()->add_package(alias, ret);
- if (!no->is_package())
- return NULL;
- }
-
- return ret;
-}
-
-// Register a package. This package may or may not be imported. This
-// returns the Package structure for the package, creating if it
-// necessary. LOCATION is the location of the import statement that
-// led us to see this package.
-
-Package*
-Gogo::register_package(const std::string& pkgpath, Location location)
-{
- Package* package = NULL;
- std::pair<Packages::iterator, bool> ins =
- this->packages_.insert(std::make_pair(pkgpath, package));
- if (!ins.second)
- {
- // We have seen this package name before.
- package = ins.first->second;
- go_assert(package != NULL && package->pkgpath() == pkgpath);
- if (Linemap::is_unknown_location(package->location()))
- package->set_location(location);
- }
- else
- {
- // First time we have seen this package name.
- package = new Package(pkgpath, location);
- go_assert(ins.first->second == NULL);
- ins.first->second = package;
- }
-
- return package;
-}
-
-// Start compiling a function.
-
-Named_object*
-Gogo::start_function(const std::string& name, Function_type* type,
- bool add_method_to_type, Location location)
-{
- bool at_top_level = this->functions_.empty();
-
- Block* block = new Block(NULL, location);
-
- Function* enclosing = (at_top_level
- ? NULL
- : this->functions_.back().function->func_value());
-
- Function* function = new Function(type, enclosing, block, location);
-
- if (type->is_method())
- {
- const Typed_identifier* receiver = type->receiver();
- Variable* this_param = new Variable(receiver->type(), NULL, false,
- true, true, location);
- std::string rname = receiver->name();
- if (rname.empty() || Gogo::is_sink_name(rname))
- {
- // We need to give receivers a name since they wind up in
- // DECL_ARGUMENTS. FIXME.
- static unsigned int count;
- char buf[50];
- snprintf(buf, sizeof buf, "r.%u", count);
- ++count;
- rname = buf;
- }
- block->bindings()->add_variable(rname, NULL, this_param);
- }
-
- const Typed_identifier_list* parameters = type->parameters();
- bool is_varargs = type->is_varargs();
- if (parameters != NULL)
- {
- for (Typed_identifier_list::const_iterator p = parameters->begin();
- p != parameters->end();
- ++p)
- {
- Variable* param = new Variable(p->type(), NULL, false, true, false,
- location);
- if (is_varargs && p + 1 == parameters->end())
- param->set_is_varargs_parameter();
-
- std::string pname = p->name();
- if (pname.empty() || Gogo::is_sink_name(pname))
- {
- // We need to give parameters a name since they wind up
- // in DECL_ARGUMENTS. FIXME.
- static unsigned int count;
- char buf[50];
- snprintf(buf, sizeof buf, "p.%u", count);
- ++count;
- pname = buf;
- }
- block->bindings()->add_variable(pname, NULL, param);
- }
- }
-
- function->create_result_variables(this);
-
- const std::string* pname;
- std::string nested_name;
- bool is_init = false;
- if (Gogo::unpack_hidden_name(name) == "init" && !type->is_method())
- {
- if ((type->parameters() != NULL && !type->parameters()->empty())
- || (type->results() != NULL && !type->results()->empty()))
- error_at(location,
- "func init must have no arguments and no return values");
- // There can be multiple "init" functions, so give them each a
- // different name.
- static int init_count;
- char buf[30];
- snprintf(buf, sizeof buf, ".$init%d", init_count);
- ++init_count;
- nested_name = buf;
- pname = &nested_name;
- is_init = true;
- }
- else if (!name.empty())
- pname = &name;
- else
- {
- // Invent a name for a nested function.
- static int nested_count;
- char buf[30];
- snprintf(buf, sizeof buf, ".$nested%d", nested_count);
- ++nested_count;
- nested_name = buf;
- pname = &nested_name;
- }
-
- Named_object* ret;
- if (Gogo::is_sink_name(*pname))
- {
- static int sink_count;
- char buf[30];
- snprintf(buf, sizeof buf, ".$sink%d", sink_count);
- ++sink_count;
- ret = Named_object::make_function(buf, NULL, function);
- }
- else if (!type->is_method())
- {
- ret = this->package_->bindings()->add_function(*pname, NULL, function);
- if (!ret->is_function() || ret->func_value() != function)
- {
- // Redefinition error. Invent a name to avoid knockon
- // errors.
- static int redefinition_count;
- char buf[30];
- snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count);
- ++redefinition_count;
- ret = this->package_->bindings()->add_function(buf, NULL, function);
- }
- }
- else
- {
- if (!add_method_to_type)
- ret = Named_object::make_function(name, NULL, function);
- else
- {
- go_assert(at_top_level);
- Type* rtype = type->receiver()->type();
-
- // We want to look through the pointer created by the
- // parser, without getting an error if the type is not yet
- // defined.
- if (rtype->classification() == Type::TYPE_POINTER)
- rtype = rtype->points_to();
-
- if (rtype->is_error_type())
- ret = Named_object::make_function(name, NULL, function);
- else if (rtype->named_type() != NULL)
- {
- ret = rtype->named_type()->add_method(name, function);
- if (!ret->is_function())
- {
- // Redefinition error.
- ret = Named_object::make_function(name, NULL, function);
- }
- }
- else if (rtype->forward_declaration_type() != NULL)
- {
- Named_object* type_no =
- rtype->forward_declaration_type()->named_object();
- if (type_no->is_unknown())
- {
- // If we are seeing methods it really must be a
- // type. Declare it as such. An alternative would
- // be to support lists of methods for unknown
- // expressions. Either way the error messages if
- // this is not a type are going to get confusing.
- Named_object* declared =
- this->declare_package_type(type_no->name(),
- type_no->location());
- go_assert(declared
- == type_no->unknown_value()->real_named_object());
- }
- ret = rtype->forward_declaration_type()->add_method(name,
- function);
- }
- else
- go_unreachable();
- }
- this->package_->bindings()->add_method(ret);
- }
-
- this->functions_.resize(this->functions_.size() + 1);
- Open_function& of(this->functions_.back());
- of.function = ret;
- of.blocks.push_back(block);
-
- if (is_init)
- {
- this->init_functions_.push_back(ret);
- this->need_init_fn_ = true;
- }
-
- return ret;
-}
-
-// Finish compiling a function.
-
-void
-Gogo::finish_function(Location location)
-{
- this->finish_block(location);
- go_assert(this->functions_.back().blocks.empty());
- this->functions_.pop_back();
-}
-
-// Return the current function.
-
-Named_object*
-Gogo::current_function() const
-{
- go_assert(!this->functions_.empty());
- return this->functions_.back().function;
-}
-
-// Start a new block.
-
-void
-Gogo::start_block(Location location)
-{
- go_assert(!this->functions_.empty());
- Block* block = new Block(this->current_block(), location);
- this->functions_.back().blocks.push_back(block);
-}
-
-// Finish a block.
-
-Block*
-Gogo::finish_block(Location location)
-{
- go_assert(!this->functions_.empty());
- go_assert(!this->functions_.back().blocks.empty());
- Block* block = this->functions_.back().blocks.back();
- this->functions_.back().blocks.pop_back();
- block->set_end_location(location);
- return block;
-}
-
-// Add an erroneous name.
-
-Named_object*
-Gogo::add_erroneous_name(const std::string& name)
-{
- return this->package_->bindings()->add_erroneous_name(name);
-}
-
-// Add an unknown name.
-
-Named_object*
-Gogo::add_unknown_name(const std::string& name, Location location)
-{
- return this->package_->bindings()->add_unknown_name(name, location);
-}
-
-// Declare a function.
-
-Named_object*
-Gogo::declare_function(const std::string& name, Function_type* type,
- Location location)
-{
- if (!type->is_method())
- return this->current_bindings()->add_function_declaration(name, NULL, type,
- location);
- else
- {
- // We don't bother to add this to the list of global
- // declarations.
- Type* rtype = type->receiver()->type();
-
- // We want to look through the pointer created by the
- // parser, without getting an error if the type is not yet
- // defined.
- if (rtype->classification() == Type::TYPE_POINTER)
- rtype = rtype->points_to();
-
- if (rtype->is_error_type())
- return NULL;
- else if (rtype->named_type() != NULL)
- return rtype->named_type()->add_method_declaration(name, NULL, type,
- location);
- else if (rtype->forward_declaration_type() != NULL)
- {
- Forward_declaration_type* ftype = rtype->forward_declaration_type();
- return ftype->add_method_declaration(name, NULL, type, location);
- }
- else
- go_unreachable();
- }
-}
-
-// Add a label definition.
-
-Label*
-Gogo::add_label_definition(const std::string& label_name,
- Location location)
-{
- go_assert(!this->functions_.empty());
- Function* func = this->functions_.back().function->func_value();
- Label* label = func->add_label_definition(this, label_name, location);
- this->add_statement(Statement::make_label_statement(label, location));
- return label;
-}
-
-// Add a label reference.
-
-Label*
-Gogo::add_label_reference(const std::string& label_name,
- Location location, bool issue_goto_errors)
-{
- go_assert(!this->functions_.empty());
- Function* func = this->functions_.back().function->func_value();
- return func->add_label_reference(this, label_name, location,
- issue_goto_errors);
-}
-
-// Return the current binding state.
-
-Bindings_snapshot*
-Gogo::bindings_snapshot(Location location)
-{
- return new Bindings_snapshot(this->current_block(), location);
-}
-
-// Add a statement.
-
-void
-Gogo::add_statement(Statement* statement)
-{
- go_assert(!this->functions_.empty()
- && !this->functions_.back().blocks.empty());
- this->functions_.back().blocks.back()->add_statement(statement);
-}
-
-// Add a block.
-
-void
-Gogo::add_block(Block* block, Location location)
-{
- go_assert(!this->functions_.empty()
- && !this->functions_.back().blocks.empty());
- Statement* statement = Statement::make_block_statement(block, location);
- this->functions_.back().blocks.back()->add_statement(statement);
-}
-
-// Add a constant.
-
-Named_object*
-Gogo::add_constant(const Typed_identifier& tid, Expression* expr,
- int iota_value)
-{
- return this->current_bindings()->add_constant(tid, NULL, expr, iota_value);
-}
-
-// Add a type.
-
-void
-Gogo::add_type(const std::string& name, Type* type, Location location)
-{
- Named_object* no = this->current_bindings()->add_type(name, NULL, type,
- location);
- if (!this->in_global_scope() && no->is_type())
- {
- Named_object* f = this->functions_.back().function;
- unsigned int index;
- if (f->is_function())
- index = f->func_value()->new_local_type_index();
- else
- index = 0;
- no->type_value()->set_in_function(f, index);
- }
-}
-
-// Add a named type.
-
-void
-Gogo::add_named_type(Named_type* type)
-{
- go_assert(this->in_global_scope());
- this->current_bindings()->add_named_type(type);
-}
-
-// Declare a type.
-
-Named_object*
-Gogo::declare_type(const std::string& name, Location location)
-{
- Bindings* bindings = this->current_bindings();
- Named_object* no = bindings->add_type_declaration(name, NULL, location);
- if (!this->in_global_scope() && no->is_type_declaration())
- {
- Named_object* f = this->functions_.back().function;
- unsigned int index;
- if (f->is_function())
- index = f->func_value()->new_local_type_index();
- else
- index = 0;
- no->type_declaration_value()->set_in_function(f, index);
- }
- return no;
-}
-
-// Declare a type at the package level.
-
-Named_object*
-Gogo::declare_package_type(const std::string& name, Location location)
-{
- return this->package_->bindings()->add_type_declaration(name, NULL, location);
-}
-
-// Declare a function at the package level.
-
-Named_object*
-Gogo::declare_package_function(const std::string& name, Function_type* type,
- Location location)
-{
- return this->package_->bindings()->add_function_declaration(name, NULL, type,
- location);
-}
-
-// Define a type which was already declared.
-
-void
-Gogo::define_type(Named_object* no, Named_type* type)
-{
- this->current_bindings()->define_type(no, type);
-}
-
-// Add a variable.
-
-Named_object*
-Gogo::add_variable(const std::string& name, Variable* variable)
-{
- Named_object* no = this->current_bindings()->add_variable(name, NULL,
- variable);
-
- // In a function the middle-end wants to see a DECL_EXPR node.
- if (no != NULL
- && no->is_variable()
- && !no->var_value()->is_parameter()
- && !this->functions_.empty())
- this->add_statement(Statement::make_variable_declaration(no));
-
- return no;
-}
-
-// Add a sink--a reference to the blank identifier _.
-
-Named_object*
-Gogo::add_sink()
-{
- return Named_object::make_sink();
-}
-
-// Add a named object.
-
-void
-Gogo::add_named_object(Named_object* no)
-{
- this->current_bindings()->add_named_object(no);
-}
-
-// Mark all local variables used. This is used when some types of
-// parse error occur.
-
-void
-Gogo::mark_locals_used()
-{
- for (Open_functions::iterator pf = this->functions_.begin();
- pf != this->functions_.end();
- ++pf)
- {
- for (std::vector<Block*>::iterator pb = pf->blocks.begin();
- pb != pf->blocks.end();
- ++pb)
- (*pb)->bindings()->mark_locals_used();
- }
-}
-
-// Record that we've seen an interface type.
-
-void
-Gogo::record_interface_type(Interface_type* itype)
-{
- this->interface_types_.push_back(itype);
-}
-
-// Return a name for a thunk object.
-
-std::string
-Gogo::thunk_name()
-{
- static int thunk_count;
- char thunk_name[50];
- snprintf(thunk_name, sizeof thunk_name, "$thunk%d", thunk_count);
- ++thunk_count;
- return thunk_name;
-}
-
-// Return whether a function is a thunk.
-
-bool
-Gogo::is_thunk(const Named_object* no)
-{
- return no->name().compare(0, 6, "$thunk") == 0;
-}
-
-// Define the global names. We do this only after parsing all the
-// input files, because the program might define the global names
-// itself.
-
-void
-Gogo::define_global_names()
-{
- for (Bindings::const_declarations_iterator p =
- this->globals_->begin_declarations();
- p != this->globals_->end_declarations();
- ++p)
- {
- Named_object* global_no = p->second;
- std::string name(Gogo::pack_hidden_name(global_no->name(), false));
- Named_object* no = this->package_->bindings()->lookup(name);
- if (no == NULL)
- continue;
- no = no->resolve();
- if (no->is_type_declaration())
- {
- if (global_no->is_type())
- {
- if (no->type_declaration_value()->has_methods())
- error_at(no->location(),
- "may not define methods for global type");
- no->set_type_value(global_no->type_value());
- }
- else
- {
- error_at(no->location(), "expected type");
- Type* errtype = Type::make_error_type();
- Named_object* err =
- Named_object::make_type("erroneous_type", NULL, errtype,
- Linemap::predeclared_location());
- no->set_type_value(err->type_value());
- }
- }
- else if (no->is_unknown())
- no->unknown_value()->set_real_named_object(global_no);
- }
-
- // Give an error if any name is defined in both the package block
- // and the file block. For example, this can happen if one file
- // imports "fmt" and another file defines a global variable fmt.
- for (Bindings::const_declarations_iterator p =
- this->package_->bindings()->begin_declarations();
- p != this->package_->bindings()->end_declarations();
- ++p)
- {
- if (p->second->is_unknown()
- && p->second->unknown_value()->real_named_object() == NULL)
- {
- // No point in warning about an undefined name, as we will
- // get other errors later anyhow.
- continue;
- }
- File_block_names::const_iterator pf =
- this->file_block_names_.find(p->second->name());
- if (pf != this->file_block_names_.end())
- {
- std::string n = p->second->message_name();
- error_at(p->second->location(),
- "%qs defined as both imported name and global name",
- n.c_str());
- inform(pf->second, "%qs imported here", n.c_str());
- }
- }
-}
-
-// Clear out names in file scope.
-
-void
-Gogo::clear_file_scope()
-{
- this->package_->bindings()->clear_file_scope(this);
-
- // Warn about packages which were imported but not used.
- bool quiet = saw_errors();
- for (Packages::iterator p = this->packages_.begin();
- p != this->packages_.end();
- ++p)
- {
- Package* package = p->second;
- if (package != this->package_
- && package->is_imported()
- && !package->used()
- && !package->uses_sink_alias()
- && !quiet)
- error_at(package->location(), "imported and not used: %s",
- Gogo::message_name(package->package_name()).c_str());
- package->clear_is_imported();
- package->clear_uses_sink_alias();
- package->clear_used();
- }
-}
-
-// Queue up a type specific function for later writing. These are
-// written out in write_specific_type_functions, called after the
-// parse tree is lowered.
-
-void
-Gogo::queue_specific_type_function(Type* type, Named_type* name,
- const std::string& hash_name,
- Function_type* hash_fntype,
- const std::string& equal_name,
- Function_type* equal_fntype)
-{
- go_assert(!this->specific_type_functions_are_written_);
- go_assert(!this->in_global_scope());
- Specific_type_function* tsf = new Specific_type_function(type, name,
- hash_name,
- hash_fntype,
- equal_name,
- equal_fntype);
- this->specific_type_functions_.push_back(tsf);
-}
-
-// Look for types which need specific hash or equality functions.
-
-class Specific_type_functions : public Traverse
-{
- public:
- Specific_type_functions(Gogo* gogo)
- : Traverse(traverse_types),
- gogo_(gogo)
- { }
-
- int
- type(Type*);
-
- private:
- Gogo* gogo_;
-};
-
-int
-Specific_type_functions::type(Type* t)
-{
- Named_object* hash_fn;
- Named_object* equal_fn;
- switch (t->classification())
- {
- case Type::TYPE_NAMED:
- {
- Named_type* nt = t->named_type();
- if (!t->compare_is_identity(this->gogo_) && t->is_comparable())
- t->type_functions(this->gogo_, nt, NULL, NULL, &hash_fn, &equal_fn);
-
- // If this is a struct type, we don't want to make functions
- // for the unnamed struct.
- Type* rt = nt->real_type();
- if (rt->struct_type() == NULL)
- {
- if (Type::traverse(rt, this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- else
- {
- // If this type is defined in another package, then we don't
- // need to worry about the unexported fields.
- bool is_defined_elsewhere = nt->named_object()->package() != NULL;
- const Struct_field_list* fields = rt->struct_type()->fields();
- for (Struct_field_list::const_iterator p = fields->begin();
- p != fields->end();
- ++p)
- {
- if (is_defined_elsewhere
- && Gogo::is_hidden_name(p->field_name()))
- continue;
- if (Type::traverse(p->type(), this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
-
- return TRAVERSE_SKIP_COMPONENTS;
- }
-
- case Type::TYPE_STRUCT:
- case Type::TYPE_ARRAY:
- if (!t->compare_is_identity(this->gogo_) && t->is_comparable())
- t->type_functions(this->gogo_, NULL, NULL, NULL, &hash_fn, &equal_fn);
- break;
-
- default:
- break;
- }
-
- return TRAVERSE_CONTINUE;
-}
-
-// Write out type specific functions.
-
-void
-Gogo::write_specific_type_functions()
-{
- Specific_type_functions stf(this);
- this->traverse(&stf);
-
- while (!this->specific_type_functions_.empty())
- {
- Specific_type_function* tsf = this->specific_type_functions_.back();
- this->specific_type_functions_.pop_back();
- tsf->type->write_specific_type_functions(this, tsf->name,
- tsf->hash_name,
- tsf->hash_fntype,
- tsf->equal_name,
- tsf->equal_fntype);
- delete tsf;
- }
- this->specific_type_functions_are_written_ = true;
-}
-
-// Traverse the tree.
-
-void
-Gogo::traverse(Traverse* traverse)
-{
- // Traverse the current package first for consistency. The other
- // packages will only contain imported types, constants, and
- // declarations.
- if (this->package_->bindings()->traverse(traverse, true) == TRAVERSE_EXIT)
- return;
- for (Packages::const_iterator p = this->packages_.begin();
- p != this->packages_.end();
- ++p)
- {
- if (p->second != this->package_)
- {
- if (p->second->bindings()->traverse(traverse, true) == TRAVERSE_EXIT)
- break;
- }
- }
-}
-
-// Add a type to verify. This is used for types of sink variables, in
-// order to give appropriate error messages.
-
-void
-Gogo::add_type_to_verify(Type* type)
-{
- this->verify_types_.push_back(type);
-}
-
-// Traversal class used to verify types.
-
-class Verify_types : public Traverse
-{
- public:
- Verify_types()
- : Traverse(traverse_types)
- { }
-
- int
- type(Type*);
-};
-
-// Verify that a type is correct.
-
-int
-Verify_types::type(Type* t)
-{
- if (!t->verify())
- return TRAVERSE_SKIP_COMPONENTS;
- return TRAVERSE_CONTINUE;
-}
-
-// Verify that all types are correct.
-
-void
-Gogo::verify_types()
-{
- Verify_types traverse;
- this->traverse(&traverse);
-
- for (std::vector<Type*>::iterator p = this->verify_types_.begin();
- p != this->verify_types_.end();
- ++p)
- (*p)->verify();
- this->verify_types_.clear();
-}
-
-// Traversal class used to lower parse tree.
-
-class Lower_parse_tree : public Traverse
-{
- public:
- Lower_parse_tree(Gogo* gogo, Named_object* function)
- : Traverse(traverse_variables
- | traverse_constants
- | traverse_functions
- | traverse_statements
- | traverse_expressions),
- gogo_(gogo), function_(function), iota_value_(-1), inserter_()
- { }
-
- void
- set_inserter(const Statement_inserter* inserter)
- { this->inserter_ = *inserter; }
-
- int
- variable(Named_object*);
-
- int
- constant(Named_object*, bool);
-
- int
- function(Named_object*);
-
- int
- statement(Block*, size_t* pindex, Statement*);
-
- int
- expression(Expression**);
-
- private:
- // General IR.
- Gogo* gogo_;
- // The function we are traversing.
- Named_object* function_;
- // Value to use for the predeclared constant iota.
- int iota_value_;
- // Current statement inserter for use by expressions.
- Statement_inserter inserter_;
-};
-
-// Lower variables.
-
-int
-Lower_parse_tree::variable(Named_object* no)
-{
- if (!no->is_variable())
- return TRAVERSE_CONTINUE;
-
- if (no->is_variable() && no->var_value()->is_global())
- {
- // Global variables can have loops in their initialization
- // expressions. This is handled in lower_init_expression.
- no->var_value()->lower_init_expression(this->gogo_, this->function_,
- &this->inserter_);
- return TRAVERSE_CONTINUE;
- }
-
- // This is a local variable. We are going to return
- // TRAVERSE_SKIP_COMPONENTS here because we want to traverse the
- // initialization expression when we reach the variable declaration
- // statement. However, that means that we need to traverse the type
- // ourselves.
- if (no->var_value()->has_type())
- {
- Type* type = no->var_value()->type();
- if (type != NULL)
- {
- if (Type::traverse(type, this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- go_assert(!no->var_value()->has_pre_init());
-
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// Lower constants. We handle constants specially so that we can set
-// the right value for the predeclared constant iota. This works in
-// conjunction with the way we lower Const_expression objects.
-
-int
-Lower_parse_tree::constant(Named_object* no, bool)
-{
- Named_constant* nc = no->const_value();
-
- // Don't get into trouble if the constant's initializer expression
- // refers to the constant itself.
- if (nc->lowering())
- return TRAVERSE_CONTINUE;
- nc->set_lowering();
-
- go_assert(this->iota_value_ == -1);
- this->iota_value_ = nc->iota_value();
- nc->traverse_expression(this);
- this->iota_value_ = -1;
-
- nc->clear_lowering();
-
- // We will traverse the expression a second time, but that will be
- // fast.
-
- return TRAVERSE_CONTINUE;
-}
-
-// Lower function closure types. Record the function while lowering
-// it, so that we can pass it down when lowering an expression.
-
-int
-Lower_parse_tree::function(Named_object* no)
-{
- no->func_value()->set_closure_type();
-
- go_assert(this->function_ == NULL);
- this->function_ = no;
- int t = no->func_value()->traverse(this);
- this->function_ = NULL;
-
- if (t == TRAVERSE_EXIT)
- return t;
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// Lower statement parse trees.
-
-int
-Lower_parse_tree::statement(Block* block, size_t* pindex, Statement* sorig)
-{
- // Because we explicitly traverse the statement's contents
- // ourselves, we want to skip block statements here. There is
- // nothing to lower in a block statement.
- if (sorig->is_block_statement())
- return TRAVERSE_CONTINUE;
-
- Statement_inserter hold_inserter(this->inserter_);
- this->inserter_ = Statement_inserter(block, pindex);
-
- // Lower the expressions first.
- int t = sorig->traverse_contents(this);
- if (t == TRAVERSE_EXIT)
- {
- this->inserter_ = hold_inserter;
- return t;
- }
-
- // Keep lowering until nothing changes.
- Statement* s = sorig;
- while (true)
- {
- Statement* snew = s->lower(this->gogo_, this->function_, block,
- &this->inserter_);
- if (snew == s)
- break;
- s = snew;
- t = s->traverse_contents(this);
- if (t == TRAVERSE_EXIT)
- {
- this->inserter_ = hold_inserter;
- return t;
- }
- }
-
- if (s != sorig)
- block->replace_statement(*pindex, s);
-
- this->inserter_ = hold_inserter;
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// Lower expression parse trees.
-
-int
-Lower_parse_tree::expression(Expression** pexpr)
-{
- // We have to lower all subexpressions first, so that we can get
- // their type if necessary. This is awkward, because we don't have
- // a postorder traversal pass.
- if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- // Keep lowering until nothing changes.
- while (true)
- {
- Expression* e = *pexpr;
- Expression* enew = e->lower(this->gogo_, this->function_,
- &this->inserter_, this->iota_value_);
- if (enew == e)
- break;
- if (enew->traverse_subexpressions(this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- *pexpr = enew;
- }
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// Lower the parse tree. This is called after the parse is complete,
-// when all names should be resolved.
-
-void
-Gogo::lower_parse_tree()
-{
- Lower_parse_tree lower_parse_tree(this, NULL);
- this->traverse(&lower_parse_tree);
-}
-
-// Lower a block.
-
-void
-Gogo::lower_block(Named_object* function, Block* block)
-{
- Lower_parse_tree lower_parse_tree(this, function);
- block->traverse(&lower_parse_tree);
-}
-
-// Lower an expression. INSERTER may be NULL, in which case the
-// expression had better not need to create any temporaries.
-
-void
-Gogo::lower_expression(Named_object* function, Statement_inserter* inserter,
- Expression** pexpr)
-{
- Lower_parse_tree lower_parse_tree(this, function);
- if (inserter != NULL)
- lower_parse_tree.set_inserter(inserter);
- lower_parse_tree.expression(pexpr);
-}
-
-// Lower a constant. This is called when lowering a reference to a
-// constant. We have to make sure that the constant has already been
-// lowered.
-
-void
-Gogo::lower_constant(Named_object* no)
-{
- go_assert(no->is_const());
- Lower_parse_tree lower(this, NULL);
- lower.constant(no, false);
-}
-
-// Look for interface types to finalize methods of inherited
-// interfaces.
-
-class Finalize_methods : public Traverse
-{
- public:
- Finalize_methods(Gogo* gogo)
- : Traverse(traverse_types),
- gogo_(gogo)
- { }
-
- int
- type(Type*);
-
- private:
- Gogo* gogo_;
-};
-
-// Finalize the methods of an interface type.
-
-int
-Finalize_methods::type(Type* t)
-{
- // Check the classification so that we don't finalize the methods
- // twice for a named interface type.
- switch (t->classification())
- {
- case Type::TYPE_INTERFACE:
- t->interface_type()->finalize_methods();
- break;
-
- case Type::TYPE_NAMED:
- {
- // We have to finalize the methods of the real type first.
- // But if the real type is a struct type, then we only want to
- // finalize the methods of the field types, not of the struct
- // type itself. We don't want to add methods to the struct,
- // since it has a name.
- Named_type* nt = t->named_type();
- Type* rt = nt->real_type();
- if (rt->classification() != Type::TYPE_STRUCT)
- {
- if (Type::traverse(rt, this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- else
- {
- if (rt->struct_type()->traverse_field_types(this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
-
- nt->finalize_methods(this->gogo_);
-
- // If this type is defined in a different package, then finalize the
- // types of all the methods, since we won't see them otherwise.
- if (nt->named_object()->package() != NULL && nt->has_any_methods())
- {
- const Methods* methods = nt->methods();
- for (Methods::const_iterator p = methods->begin();
- p != methods->end();
- ++p)
- {
- if (Type::traverse(p->second->type(), this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
-
- // Finalize the types of all methods that are declared but not
- // defined, since we won't see the declarations otherwise.
- if (nt->named_object()->package() == NULL
- && nt->local_methods() != NULL)
- {
- const Bindings* methods = nt->local_methods();
- for (Bindings::const_declarations_iterator p =
- methods->begin_declarations();
- p != methods->end_declarations();
- p++)
- {
- if (p->second->is_function_declaration())
- {
- Type* mt = p->second->func_declaration_value()->type();
- if (Type::traverse(mt, this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- }
-
- return TRAVERSE_SKIP_COMPONENTS;
- }
-
- case Type::TYPE_STRUCT:
- // Traverse the field types first in case there is an embedded
- // field with methods that the struct should inherit.
- if (t->struct_type()->traverse_field_types(this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- t->struct_type()->finalize_methods(this->gogo_);
- return TRAVERSE_SKIP_COMPONENTS;
-
- default:
- break;
- }
-
- return TRAVERSE_CONTINUE;
-}
-
-// Finalize method lists and build stub methods for types.
-
-void
-Gogo::finalize_methods()
-{
- Finalize_methods finalize(this);
- this->traverse(&finalize);
-}
-
-// Set types for unspecified variables and constants.
-
-void
-Gogo::determine_types()
-{
- Bindings* bindings = this->current_bindings();
- for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
- p != bindings->end_definitions();
- ++p)
- {
- if ((*p)->is_function())
- (*p)->func_value()->determine_types();
- else if ((*p)->is_variable())
- (*p)->var_value()->determine_type();
- else if ((*p)->is_const())
- (*p)->const_value()->determine_type();
-
- // See if a variable requires us to build an initialization
- // function. We know that we will see all global variables
- // here.
- if (!this->need_init_fn_ && (*p)->is_variable())
- {
- Variable* variable = (*p)->var_value();
-
- // If this is a global variable which requires runtime
- // initialization, we need an initialization function.
- if (!variable->is_global())
- ;
- else if (variable->init() == NULL)
- ;
- else if (variable->type()->interface_type() != NULL)
- this->need_init_fn_ = true;
- else if (variable->init()->is_constant())
- ;
- else if (!variable->init()->is_composite_literal())
- this->need_init_fn_ = true;
- else if (variable->init()->is_nonconstant_composite_literal())
- this->need_init_fn_ = true;
-
- // If this is a global variable which holds a pointer value,
- // then we need an initialization function to register it as a
- // GC root.
- if (variable->is_global() && variable->type()->has_pointer())
- this->need_init_fn_ = true;
- }
- }
-
- // Determine the types of constants in packages.
- for (Packages::const_iterator p = this->packages_.begin();
- p != this->packages_.end();
- ++p)
- p->second->determine_types();
-}
-
-// Traversal class used for type checking.
-
-class Check_types_traverse : public Traverse
-{
- public:
- Check_types_traverse(Gogo* gogo)
- : Traverse(traverse_variables
- | traverse_constants
- | traverse_functions
- | traverse_statements
- | traverse_expressions),
- gogo_(gogo)
- { }
-
- int
- variable(Named_object*);
-
- int
- constant(Named_object*, bool);
-
- int
- function(Named_object*);
-
- int
- statement(Block*, size_t* pindex, Statement*);
-
- int
- expression(Expression**);
-
- private:
- // General IR.
- Gogo* gogo_;
-};
-
-// Check that a variable initializer has the right type.
-
-int
-Check_types_traverse::variable(Named_object* named_object)
-{
- if (named_object->is_variable())
- {
- Variable* var = named_object->var_value();
-
- // Give error if variable type is not defined.
- var->type()->base();
-
- Expression* init = var->init();
- std::string reason;
- if (init != NULL
- && !Type::are_assignable(var->type(), init->type(), &reason))
- {
- if (reason.empty())
- error_at(var->location(), "incompatible type in initialization");
- else
- error_at(var->location(),
- "incompatible type in initialization (%s)",
- reason.c_str());
- var->clear_init();
- }
- else if (!var->is_used()
- && !var->is_global()
- && !var->is_parameter()
- && !var->is_receiver()
- && !var->type()->is_error()
- && (init == NULL || !init->is_error_expression())
- && !Lex::is_invalid_identifier(named_object->name()))
- error_at(var->location(), "%qs declared and not used",
- named_object->message_name().c_str());
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Check that a constant initializer has the right type.
-
-int
-Check_types_traverse::constant(Named_object* named_object, bool)
-{
- Named_constant* constant = named_object->const_value();
- Type* ctype = constant->type();
- if (ctype->integer_type() == NULL
- && ctype->float_type() == NULL
- && ctype->complex_type() == NULL
- && !ctype->is_boolean_type()
- && !ctype->is_string_type())
- {
- if (ctype->is_nil_type())
- error_at(constant->location(), "const initializer cannot be nil");
- else if (!ctype->is_error())
- error_at(constant->location(), "invalid constant type");
- constant->set_error();
- }
- else if (!constant->expr()->is_constant())
- {
- error_at(constant->expr()->location(), "expression is not constant");
- constant->set_error();
- }
- else if (!Type::are_assignable(constant->type(), constant->expr()->type(),
- NULL))
- {
- error_at(constant->location(),
- "initialization expression has wrong type");
- constant->set_error();
- }
- return TRAVERSE_CONTINUE;
-}
-
-// There are no types to check in a function, but this is where we
-// issue warnings about labels which are defined but not referenced.
-
-int
-Check_types_traverse::function(Named_object* no)
-{
- no->func_value()->check_labels();
- return TRAVERSE_CONTINUE;
-}
-
-// Check that types are valid in a statement.
-
-int
-Check_types_traverse::statement(Block*, size_t*, Statement* s)
-{
- s->check_types(this->gogo_);
- return TRAVERSE_CONTINUE;
-}
-
-// Check that types are valid in an expression.
-
-int
-Check_types_traverse::expression(Expression** expr)
-{
- (*expr)->check_types(this->gogo_);
- return TRAVERSE_CONTINUE;
-}
-
-// Check that types are valid.
-
-void
-Gogo::check_types()
-{
- Check_types_traverse traverse(this);
- this->traverse(&traverse);
-}
-
-// Check the types in a single block.
-
-void
-Gogo::check_types_in_block(Block* block)
-{
- Check_types_traverse traverse(this);
- block->traverse(&traverse);
-}
-
-// A traversal class used to find a single shortcut operator within an
-// expression.
-
-class Find_shortcut : public Traverse
-{
- public:
- Find_shortcut()
- : Traverse(traverse_blocks
- | traverse_statements
- | traverse_expressions),
- found_(NULL)
- { }
-
- // A pointer to the expression which was found, or NULL if none was
- // found.
- Expression**
- found() const
- { return this->found_; }
-
- protected:
- int
- block(Block*)
- { return TRAVERSE_SKIP_COMPONENTS; }
-
- int
- statement(Block*, size_t*, Statement*)
- { return TRAVERSE_SKIP_COMPONENTS; }
-
- int
- expression(Expression**);
-
- private:
- Expression** found_;
-};
-
-// Find a shortcut expression.
-
-int
-Find_shortcut::expression(Expression** pexpr)
-{
- Expression* expr = *pexpr;
- Binary_expression* be = expr->binary_expression();
- if (be == NULL)
- return TRAVERSE_CONTINUE;
- Operator op = be->op();
- if (op != OPERATOR_OROR && op != OPERATOR_ANDAND)
- return TRAVERSE_CONTINUE;
- go_assert(this->found_ == NULL);
- this->found_ = pexpr;
- return TRAVERSE_EXIT;
-}
-
-// A traversal class used to turn shortcut operators into explicit if
-// statements.
-
-class Shortcuts : public Traverse
-{
- public:
- Shortcuts(Gogo* gogo)
- : Traverse(traverse_variables
- | traverse_statements),
- gogo_(gogo)
- { }
-
- protected:
- int
- variable(Named_object*);
-
- int
- statement(Block*, size_t*, Statement*);
-
- private:
- // Convert a shortcut operator.
- Statement*
- convert_shortcut(Block* enclosing, Expression** pshortcut);
-
- // The IR.
- Gogo* gogo_;
-};
-
-// Remove shortcut operators in a single statement.
-
-int
-Shortcuts::statement(Block* block, size_t* pindex, Statement* s)
-{
- // FIXME: This approach doesn't work for switch statements, because
- // we add the new statements before the whole switch when we need to
- // instead add them just before the switch expression. The right
- // fix is probably to lower switch statements with nonconstant cases
- // to a series of conditionals.
- if (s->switch_statement() != NULL)
- return TRAVERSE_CONTINUE;
-
- while (true)
- {
- Find_shortcut find_shortcut;
-
- // If S is a variable declaration, then ordinary traversal won't
- // do anything. We want to explicitly traverse the
- // initialization expression if there is one.
- Variable_declaration_statement* vds = s->variable_declaration_statement();
- Expression* init = NULL;
- if (vds == NULL)
- s->traverse_contents(&find_shortcut);
- else
- {
- init = vds->var()->var_value()->init();
- if (init == NULL)
- return TRAVERSE_CONTINUE;
- init->traverse(&init, &find_shortcut);
- }
- Expression** pshortcut = find_shortcut.found();
- if (pshortcut == NULL)
- return TRAVERSE_CONTINUE;
-
- Statement* snew = this->convert_shortcut(block, pshortcut);
- block->insert_statement_before(*pindex, snew);
- ++*pindex;
-
- if (pshortcut == &init)
- vds->var()->var_value()->set_init(init);
- }
-}
-
-// Remove shortcut operators in the initializer of a global variable.
-
-int
-Shortcuts::variable(Named_object* no)
-{
- if (no->is_result_variable())
- return TRAVERSE_CONTINUE;
- Variable* var = no->var_value();
- Expression* init = var->init();
- if (!var->is_global() || init == NULL)
- return TRAVERSE_CONTINUE;
-
- while (true)
- {
- Find_shortcut find_shortcut;
- init->traverse(&init, &find_shortcut);
- Expression** pshortcut = find_shortcut.found();
- if (pshortcut == NULL)
- return TRAVERSE_CONTINUE;
-
- Statement* snew = this->convert_shortcut(NULL, pshortcut);
- var->add_preinit_statement(this->gogo_, snew);
- if (pshortcut == &init)
- var->set_init(init);
- }
-}
-
-// Given an expression which uses a shortcut operator, return a
-// statement which implements it, and update *PSHORTCUT accordingly.
-
-Statement*
-Shortcuts::convert_shortcut(Block* enclosing, Expression** pshortcut)
-{
- Binary_expression* shortcut = (*pshortcut)->binary_expression();
- Expression* left = shortcut->left();
- Expression* right = shortcut->right();
- Location loc = shortcut->location();
-
- Block* retblock = new Block(enclosing, loc);
- retblock->set_end_location(loc);
-
- Temporary_statement* ts = Statement::make_temporary(Type::lookup_bool_type(),
- left, loc);
- retblock->add_statement(ts);
-
- Block* block = new Block(retblock, loc);
- block->set_end_location(loc);
- Expression* tmpref = Expression::make_temporary_reference(ts, loc);
- Statement* assign = Statement::make_assignment(tmpref, right, loc);
- block->add_statement(assign);
-
- Expression* cond = Expression::make_temporary_reference(ts, loc);
- if (shortcut->binary_expression()->op() == OPERATOR_OROR)
- cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
-
- Statement* if_statement = Statement::make_if_statement(cond, block, NULL,
- loc);
- retblock->add_statement(if_statement);
-
- *pshortcut = Expression::make_temporary_reference(ts, loc);
-
- delete shortcut;
-
- // Now convert any shortcut operators in LEFT and RIGHT.
- Shortcuts shortcuts(this->gogo_);
- retblock->traverse(&shortcuts);
-
- return Statement::make_block_statement(retblock, loc);
-}
-
-// Turn shortcut operators into explicit if statements. Doing this
-// considerably simplifies the order of evaluation rules.
-
-void
-Gogo::remove_shortcuts()
-{
- Shortcuts shortcuts(this);
- this->traverse(&shortcuts);
-}
-
-// A traversal class which finds all the expressions which must be
-// evaluated in order within a statement or larger expression. This
-// is used to implement the rules about order of evaluation.
-
-class Find_eval_ordering : public Traverse
-{
- private:
- typedef std::vector<Expression**> Expression_pointers;
-
- public:
- Find_eval_ordering()
- : Traverse(traverse_blocks
- | traverse_statements
- | traverse_expressions),
- exprs_()
- { }
-
- size_t
- size() const
- { return this->exprs_.size(); }
-
- typedef Expression_pointers::const_iterator const_iterator;
-
- const_iterator
- begin() const
- { return this->exprs_.begin(); }
-
- const_iterator
- end() const
- { return this->exprs_.end(); }
-
- protected:
- int
- block(Block*)
- { return TRAVERSE_SKIP_COMPONENTS; }
-
- int
- statement(Block*, size_t*, Statement*)
- { return TRAVERSE_SKIP_COMPONENTS; }
-
- int
- expression(Expression**);
-
- private:
- // A list of pointers to expressions with side-effects.
- Expression_pointers exprs_;
-};
-
-// If an expression must be evaluated in order, put it on the list.
-
-int
-Find_eval_ordering::expression(Expression** expression_pointer)
-{
- // We have to look at subexpressions before this one.
- if ((*expression_pointer)->traverse_subexpressions(this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if ((*expression_pointer)->must_eval_in_order())
- this->exprs_.push_back(expression_pointer);
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// A traversal class for ordering evaluations.
-
-class Order_eval : public Traverse
-{
- public:
- Order_eval(Gogo* gogo)
- : Traverse(traverse_variables
- | traverse_statements),
- gogo_(gogo)
- { }
-
- int
- variable(Named_object*);
-
- int
- statement(Block*, size_t*, Statement*);
-
- private:
- // The IR.
- Gogo* gogo_;
-};
-
-// Implement the order of evaluation rules for a statement.
-
-int
-Order_eval::statement(Block* block, size_t* pindex, Statement* s)
-{
- // FIXME: This approach doesn't work for switch statements, because
- // we add the new statements before the whole switch when we need to
- // instead add them just before the switch expression. The right
- // fix is probably to lower switch statements with nonconstant cases
- // to a series of conditionals.
- if (s->switch_statement() != NULL)
- return TRAVERSE_CONTINUE;
-
- Find_eval_ordering find_eval_ordering;
-
- // If S is a variable declaration, then ordinary traversal won't do
- // anything. We want to explicitly traverse the initialization
- // expression if there is one.
- Variable_declaration_statement* vds = s->variable_declaration_statement();
- Expression* init = NULL;
- Expression* orig_init = NULL;
- if (vds == NULL)
- s->traverse_contents(&find_eval_ordering);
- else
- {
- init = vds->var()->var_value()->init();
- if (init == NULL)
- return TRAVERSE_CONTINUE;
- orig_init = init;
-
- // It might seem that this could be
- // init->traverse_subexpressions. Unfortunately that can fail
- // in a case like
- // var err os.Error
- // newvar, err := call(arg())
- // Here newvar will have an init of call result 0 of
- // call(arg()). If we only traverse subexpressions, we will
- // only find arg(), and we won't bother to move anything out.
- // Then we get to the assignment to err, we will traverse the
- // whole statement, and this time we will find both call() and
- // arg(), and so we will move them out. This will cause them to
- // be put into temporary variables before the assignment to err
- // but after the declaration of newvar. To avoid that problem,
- // we traverse the entire expression here.
- Expression::traverse(&init, &find_eval_ordering);
- }
-
- size_t c = find_eval_ordering.size();
- if (c == 0)
- return TRAVERSE_CONTINUE;
-
- // If there is only one expression with a side-effect, we can
- // usually leave it in place. However, for an assignment statement,
- // we need to evaluate an expression on the right hand side before
- // we evaluate any index expression on the left hand side, so for
- // that case we always move the expression. Otherwise we mishandle
- // m[0] = len(m) where m is a map.
- if (c == 1 && s->classification() != Statement::STATEMENT_ASSIGNMENT)
- return TRAVERSE_CONTINUE;
-
- bool is_thunk = s->thunk_statement() != NULL;
- for (Find_eval_ordering::const_iterator p = find_eval_ordering.begin();
- p != find_eval_ordering.end();
- ++p)
- {
- Expression** pexpr = *p;
-
- // The last expression in a thunk will be the call passed to go
- // or defer, which we must not evaluate early.
- if (is_thunk && p + 1 == find_eval_ordering.end())
- break;
-
- Location loc = (*pexpr)->location();
- Statement* s;
- if ((*pexpr)->call_expression() == NULL
- || (*pexpr)->call_expression()->result_count() < 2)
- {
- Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr,
- loc);
- s = ts;
- *pexpr = Expression::make_temporary_reference(ts, loc);
- }
- else
- {
- // A call expression which returns multiple results needs to
- // be handled specially. We can't create a temporary
- // because there is no type to give it. Any actual uses of
- // the values will be done via Call_result_expressions.
- s = Statement::make_statement(*pexpr, true);
- }
-
- block->insert_statement_before(*pindex, s);
- ++*pindex;
- }
-
- if (init != orig_init)
- vds->var()->var_value()->set_init(init);
-
- return TRAVERSE_CONTINUE;
-}
-
-// Implement the order of evaluation rules for the initializer of a
-// global variable.
-
-int
-Order_eval::variable(Named_object* no)
-{
- if (no->is_result_variable())
- return TRAVERSE_CONTINUE;
- Variable* var = no->var_value();
- Expression* init = var->init();
- if (!var->is_global() || init == NULL)
- return TRAVERSE_CONTINUE;
-
- Find_eval_ordering find_eval_ordering;
- Expression::traverse(&init, &find_eval_ordering);
-
- if (find_eval_ordering.size() <= 1)
- {
- // If there is only one expression with a side-effect, we can
- // leave it in place.
- return TRAVERSE_SKIP_COMPONENTS;
- }
-
- Expression* orig_init = init;
-
- for (Find_eval_ordering::const_iterator p = find_eval_ordering.begin();
- p != find_eval_ordering.end();
- ++p)
- {
- Expression** pexpr = *p;
- Location loc = (*pexpr)->location();
- Statement* s;
- if ((*pexpr)->call_expression() == NULL
- || (*pexpr)->call_expression()->result_count() < 2)
- {
- Temporary_statement* ts = Statement::make_temporary(NULL, *pexpr,
- loc);
- s = ts;
- *pexpr = Expression::make_temporary_reference(ts, loc);
- }
- else
- {
- // A call expression which returns multiple results needs to
- // be handled specially.
- s = Statement::make_statement(*pexpr, true);
- }
- var->add_preinit_statement(this->gogo_, s);
- }
-
- if (init != orig_init)
- var->set_init(init);
-
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// Use temporary variables to implement the order of evaluation rules.
-
-void
-Gogo::order_evaluations()
-{
- Order_eval order_eval(this);
- this->traverse(&order_eval);
-}
-
-// Traversal to convert calls to the predeclared recover function to
-// pass in an argument indicating whether it can recover from a panic
-// or not.
-
-class Convert_recover : public Traverse
-{
- public:
- Convert_recover(Named_object* arg)
- : Traverse(traverse_expressions),
- arg_(arg)
- { }
-
- protected:
- int
- expression(Expression**);
-
- private:
- // The argument to pass to the function.
- Named_object* arg_;
-};
-
-// Convert calls to recover.
-
-int
-Convert_recover::expression(Expression** pp)
-{
- Call_expression* ce = (*pp)->call_expression();
- if (ce != NULL && ce->is_recover_call())
- ce->set_recover_arg(Expression::make_var_reference(this->arg_,
- ce->location()));
- return TRAVERSE_CONTINUE;
-}
-
-// Traversal for build_recover_thunks.
-
-class Build_recover_thunks : public Traverse
-{
- public:
- Build_recover_thunks(Gogo* gogo)
- : Traverse(traverse_functions),
- gogo_(gogo)
- { }
-
- int
- function(Named_object*);
-
- private:
- Expression*
- can_recover_arg(Location);
-
- // General IR.
- Gogo* gogo_;
-};
-
-// If this function calls recover, turn it into a thunk.
-
-int
-Build_recover_thunks::function(Named_object* orig_no)
-{
- Function* orig_func = orig_no->func_value();
- if (!orig_func->calls_recover()
- || orig_func->is_recover_thunk()
- || orig_func->has_recover_thunk())
- return TRAVERSE_CONTINUE;
-
- Gogo* gogo = this->gogo_;
- Location location = orig_func->location();
-
- static int count;
- char buf[50];
-
- Function_type* orig_fntype = orig_func->type();
- Typed_identifier_list* new_params = new Typed_identifier_list();
- std::string receiver_name;
- if (orig_fntype->is_method())
- {
- const Typed_identifier* receiver = orig_fntype->receiver();
- snprintf(buf, sizeof buf, "rt.%u", count);
- ++count;
- receiver_name = buf;
- new_params->push_back(Typed_identifier(receiver_name, receiver->type(),
- receiver->location()));
- }
- const Typed_identifier_list* orig_params = orig_fntype->parameters();
- if (orig_params != NULL && !orig_params->empty())
- {
- for (Typed_identifier_list::const_iterator p = orig_params->begin();
- p != orig_params->end();
- ++p)
- {
- snprintf(buf, sizeof buf, "pt.%u", count);
- ++count;
- new_params->push_back(Typed_identifier(buf, p->type(),
- p->location()));
- }
- }
- snprintf(buf, sizeof buf, "pr.%u", count);
- ++count;
- std::string can_recover_name = buf;
- new_params->push_back(Typed_identifier(can_recover_name,
- Type::lookup_bool_type(),
- orig_fntype->location()));
-
- const Typed_identifier_list* orig_results = orig_fntype->results();
- Typed_identifier_list* new_results;
- if (orig_results == NULL || orig_results->empty())
- new_results = NULL;
- else
- {
- new_results = new Typed_identifier_list();
- for (Typed_identifier_list::const_iterator p = orig_results->begin();
- p != orig_results->end();
- ++p)
- new_results->push_back(Typed_identifier("", p->type(), p->location()));
- }
-
- Function_type *new_fntype = Type::make_function_type(NULL, new_params,
- new_results,
- orig_fntype->location());
- if (orig_fntype->is_varargs())
- new_fntype->set_is_varargs();
-
- std::string name = orig_no->name() + "$recover";
- Named_object *new_no = gogo->start_function(name, new_fntype, false,
- location);
- Function *new_func = new_no->func_value();
- if (orig_func->enclosing() != NULL)
- new_func->set_enclosing(orig_func->enclosing());
-
- // We build the code for the original function attached to the new
- // function, and then swap the original and new function bodies.
- // This means that existing references to the original function will
- // then refer to the new function. That makes this code a little
- // confusing, in that the reference to NEW_NO really refers to the
- // other function, not the one we are building.
-
- Expression* closure = NULL;
- if (orig_func->needs_closure())
- {
- Named_object* orig_closure_no = orig_func->closure_var();
- Variable* orig_closure_var = orig_closure_no->var_value();
- Variable* new_var = new Variable(orig_closure_var->type(), NULL, false,
- true, false, location);
- snprintf(buf, sizeof buf, "closure.%u", count);
- ++count;
- Named_object* new_closure_no = Named_object::make_variable(buf, NULL,
- new_var);
- new_func->set_closure_var(new_closure_no);
- closure = Expression::make_var_reference(new_closure_no, location);
- }
-
- Expression* fn = Expression::make_func_reference(new_no, closure, location);
-
- Expression_list* args = new Expression_list();
- if (new_params != NULL)
- {
- // Note that we skip the last parameter, which is the boolean
- // indicating whether recover can succed.
- for (Typed_identifier_list::const_iterator p = new_params->begin();
- p + 1 != new_params->end();
- ++p)
- {
- Named_object* p_no = gogo->lookup(p->name(), NULL);
- go_assert(p_no != NULL
- && p_no->is_variable()
- && p_no->var_value()->is_parameter());
- args->push_back(Expression::make_var_reference(p_no, location));
- }
- }
- args->push_back(this->can_recover_arg(location));
-
- gogo->start_block(location);
-
- Call_expression* call = Expression::make_call(fn, args, false, location);
-
- // Any varargs call has already been lowered.
- call->set_varargs_are_lowered();
-
- Statement* s;
- if (orig_fntype->results() == NULL || orig_fntype->results()->empty())
- s = Statement::make_statement(call, true);
- else
- {
- Expression_list* vals = new Expression_list();
- size_t rc = orig_fntype->results()->size();
- if (rc == 1)
- vals->push_back(call);
- else
- {
- for (size_t i = 0; i < rc; ++i)
- vals->push_back(Expression::make_call_result(call, i));
- }
- s = Statement::make_return_statement(vals, location);
- }
- s->determine_types();
- gogo->add_statement(s);
-
- Block* b = gogo->finish_block(location);
-
- gogo->add_block(b, location);
-
- // Lower the call in case it returns multiple results.
- gogo->lower_block(new_no, b);
-
- gogo->finish_function(location);
-
- // Swap the function bodies and types.
- new_func->swap_for_recover(orig_func);
- orig_func->set_is_recover_thunk();
- new_func->set_calls_recover();
- new_func->set_has_recover_thunk();
-
- Bindings* orig_bindings = orig_func->block()->bindings();
- Bindings* new_bindings = new_func->block()->bindings();
- if (orig_fntype->is_method())
- {
- // We changed the receiver to be a regular parameter. We have
- // to update the binding accordingly in both functions.
- Named_object* orig_rec_no = orig_bindings->lookup_local(receiver_name);
- go_assert(orig_rec_no != NULL
- && orig_rec_no->is_variable()
- && !orig_rec_no->var_value()->is_receiver());
- orig_rec_no->var_value()->set_is_receiver();
-
- const std::string& new_receiver_name(orig_fntype->receiver()->name());
- Named_object* new_rec_no = new_bindings->lookup_local(new_receiver_name);
- if (new_rec_no == NULL)
- go_assert(saw_errors());
- else
- {
- go_assert(new_rec_no->is_variable()
- && new_rec_no->var_value()->is_receiver());
- new_rec_no->var_value()->set_is_not_receiver();
- }
- }
-
- // Because we flipped blocks but not types, the can_recover
- // parameter appears in the (now) old bindings as a parameter.
- // Change it to a local variable, whereupon it will be discarded.
- Named_object* can_recover_no = orig_bindings->lookup_local(can_recover_name);
- go_assert(can_recover_no != NULL
- && can_recover_no->is_variable()
- && can_recover_no->var_value()->is_parameter());
- orig_bindings->remove_binding(can_recover_no);
-
- // Add the can_recover argument to the (now) new bindings, and
- // attach it to any recover statements.
- Variable* can_recover_var = new Variable(Type::lookup_bool_type(), NULL,
- false, true, false, location);
- can_recover_no = new_bindings->add_variable(can_recover_name, NULL,
- can_recover_var);
- Convert_recover convert_recover(can_recover_no);
- new_func->traverse(&convert_recover);
-
- // Update the function pointers in any named results.
- new_func->update_result_variables();
- orig_func->update_result_variables();
-
- return TRAVERSE_CONTINUE;
-}
-
-// Return the expression to pass for the .can_recover parameter to the
-// new function. This indicates whether a call to recover may return
-// non-nil. The expression is
-// __go_can_recover(__builtin_return_address()).
-
-Expression*
-Build_recover_thunks::can_recover_arg(Location location)
-{
- static Named_object* builtin_return_address;
- if (builtin_return_address == NULL)
- {
- const Location bloc = Linemap::predeclared_location();
-
- Typed_identifier_list* param_types = new Typed_identifier_list();
- Type* uint_type = Type::lookup_integer_type("uint");
- param_types->push_back(Typed_identifier("l", uint_type, bloc));
-
- Typed_identifier_list* return_types = new Typed_identifier_list();
- Type* voidptr_type = Type::make_pointer_type(Type::make_void_type());
- return_types->push_back(Typed_identifier("", voidptr_type, bloc));
-
- Function_type* fntype = Type::make_function_type(NULL, param_types,
- return_types, bloc);
- builtin_return_address =
- Named_object::make_function_declaration("__builtin_return_address",
- NULL, fntype, bloc);
- const char* n = "__builtin_return_address";
- builtin_return_address->func_declaration_value()->set_asm_name(n);
- }
-
- static Named_object* can_recover;
- if (can_recover == NULL)
- {
- const Location bloc = Linemap::predeclared_location();
- Typed_identifier_list* param_types = new Typed_identifier_list();
- Type* voidptr_type = Type::make_pointer_type(Type::make_void_type());
- param_types->push_back(Typed_identifier("a", voidptr_type, bloc));
- Type* boolean_type = Type::lookup_bool_type();
- Typed_identifier_list* results = new Typed_identifier_list();
- results->push_back(Typed_identifier("", boolean_type, bloc));
- Function_type* fntype = Type::make_function_type(NULL, param_types,
- results, bloc);
- can_recover = Named_object::make_function_declaration("__go_can_recover",
- NULL, fntype,
- bloc);
- can_recover->func_declaration_value()->set_asm_name("__go_can_recover");
- }
-
- Expression* fn = Expression::make_func_reference(builtin_return_address,
- NULL, location);
-
- mpz_t zval;
- mpz_init_set_ui(zval, 0UL);
- Expression* zexpr = Expression::make_integer(&zval, NULL, location);
- mpz_clear(zval);
- Expression_list *args = new Expression_list();
- args->push_back(zexpr);
-
- Expression* call = Expression::make_call(fn, args, false, location);
-
- args = new Expression_list();
- args->push_back(call);
-
- fn = Expression::make_func_reference(can_recover, NULL, location);
- return Expression::make_call(fn, args, false, location);
-}
-
-// Build thunks for functions which call recover. We build a new
-// function with an extra parameter, which is whether a call to
-// recover can succeed. We then move the body of this function to
-// that one. We then turn this function into a thunk which calls the
-// new one, passing the value of
-// __go_can_recover(__builtin_return_address()). The function will be
-// marked as not splitting the stack. This will cooperate with the
-// implementation of defer to make recover do the right thing.
-
-void
-Gogo::build_recover_thunks()
-{
- Build_recover_thunks build_recover_thunks(this);
- this->traverse(&build_recover_thunks);
-}
-
-// Look for named types to see whether we need to create an interface
-// method table.
-
-class Build_method_tables : public Traverse
-{
- public:
- Build_method_tables(Gogo* gogo,
- const std::vector<Interface_type*>& interfaces)
- : Traverse(traverse_types),
- gogo_(gogo), interfaces_(interfaces)
- { }
-
- int
- type(Type*);
-
- private:
- // The IR.
- Gogo* gogo_;
- // A list of locally defined interfaces which have hidden methods.
- const std::vector<Interface_type*>& interfaces_;
-};
-
-// Build all required interface method tables for types. We need to
-// ensure that we have an interface method table for every interface
-// which has a hidden method, for every named type which implements
-// that interface. Normally we can just build interface method tables
-// as we need them. However, in some cases we can require an
-// interface method table for an interface defined in a different
-// package for a type defined in that package. If that interface and
-// type both use a hidden method, that is OK. However, we will not be
-// able to build that interface method table when we need it, because
-// the type's hidden method will be static. So we have to build it
-// here, and just refer it from other packages as needed.
-
-void
-Gogo::build_interface_method_tables()
-{
- if (saw_errors())
- return;
-
- std::vector<Interface_type*> hidden_interfaces;
- hidden_interfaces.reserve(this->interface_types_.size());
- for (std::vector<Interface_type*>::const_iterator pi =
- this->interface_types_.begin();
- pi != this->interface_types_.end();
- ++pi)
- {
- const Typed_identifier_list* methods = (*pi)->methods();
- if (methods == NULL)
- continue;
- for (Typed_identifier_list::const_iterator pm = methods->begin();
- pm != methods->end();
- ++pm)
- {
- if (Gogo::is_hidden_name(pm->name()))
- {
- hidden_interfaces.push_back(*pi);
- break;
- }
- }
- }
-
- if (!hidden_interfaces.empty())
- {
- // Now traverse the tree looking for all named types.
- Build_method_tables bmt(this, hidden_interfaces);
- this->traverse(&bmt);
- }
-
- // We no longer need the list of interfaces.
-
- this->interface_types_.clear();
-}
-
-// This is called for each type. For a named type, for each of the
-// interfaces with hidden methods that it implements, create the
-// method table.
-
-int
-Build_method_tables::type(Type* type)
-{
- Named_type* nt = type->named_type();
- Struct_type* st = type->struct_type();
- if (nt != NULL || st != NULL)
- {
- for (std::vector<Interface_type*>::const_iterator p =
- this->interfaces_.begin();
- p != this->interfaces_.end();
- ++p)
- {
- // We ask whether a pointer to the named type implements the
- // interface, because a pointer can implement more methods
- // than a value.
- if (nt != NULL)
- {
- if ((*p)->implements_interface(Type::make_pointer_type(nt),
- NULL))
- {
- nt->interface_method_table(this->gogo_, *p, false);
- nt->interface_method_table(this->gogo_, *p, true);
- }
- }
- else
- {
- if ((*p)->implements_interface(Type::make_pointer_type(st),
- NULL))
- {
- st->interface_method_table(this->gogo_, *p, false);
- st->interface_method_table(this->gogo_, *p, true);
- }
- }
- }
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Traversal class used to check for return statements.
-
-class Check_return_statements_traverse : public Traverse
-{
- public:
- Check_return_statements_traverse()
- : Traverse(traverse_functions)
- { }
-
- int
- function(Named_object*);
-};
-
-// Check that a function has a return statement if it needs one.
-
-int
-Check_return_statements_traverse::function(Named_object* no)
-{
- Function* func = no->func_value();
- const Function_type* fntype = func->type();
- const Typed_identifier_list* results = fntype->results();
-
- // We only need a return statement if there is a return value.
- if (results == NULL || results->empty())
- return TRAVERSE_CONTINUE;
-
- if (func->block()->may_fall_through())
- error_at(func->location(), "control reaches end of non-void function");
-
- return TRAVERSE_CONTINUE;
-}
-
-// Check return statements.
-
-void
-Gogo::check_return_statements()
-{
- Check_return_statements_traverse traverse;
- this->traverse(&traverse);
-}
-
-// Work out the package priority. It is one more than the maximum
-// priority of an imported package.
-
-int
-Gogo::package_priority() const
-{
- int priority = 0;
- for (Packages::const_iterator p = this->packages_.begin();
- p != this->packages_.end();
- ++p)
- if (p->second->priority() > priority)
- priority = p->second->priority();
- return priority + 1;
-}
-
-// Export identifiers as requested.
-
-void
-Gogo::do_exports()
-{
- // For now we always stream to a section. Later we may want to
- // support streaming to a separate file.
- Stream_to_section stream;
-
- Export exp(&stream);
- exp.register_builtin_types(this);
- exp.export_globals(this->package_name(),
- this->pkgpath(),
- this->package_priority(),
- this->imports_,
- (this->need_init_fn_ && !this->is_main_package()
- ? this->get_init_fn_name()
- : ""),
- this->imported_init_fns_,
- this->package_->bindings());
-}
-
-// Find the blocks in order to convert named types defined in blocks.
-
-class Convert_named_types : public Traverse
-{
- public:
- Convert_named_types(Gogo* gogo)
- : Traverse(traverse_blocks),
- gogo_(gogo)
- { }
-
- protected:
- int
- block(Block* block);
-
- private:
- Gogo* gogo_;
-};
-
-int
-Convert_named_types::block(Block* block)
-{
- this->gogo_->convert_named_types_in_bindings(block->bindings());
- return TRAVERSE_CONTINUE;
-}
-
-// Convert all named types to the backend representation. Since named
-// types can refer to other types, this needs to be done in the right
-// sequence, which is handled by Named_type::convert. Here we arrange
-// to call that for each named type.
-
-void
-Gogo::convert_named_types()
-{
- this->convert_named_types_in_bindings(this->globals_);
- for (Packages::iterator p = this->packages_.begin();
- p != this->packages_.end();
- ++p)
- {
- Package* package = p->second;
- this->convert_named_types_in_bindings(package->bindings());
- }
-
- Convert_named_types cnt(this);
- this->traverse(&cnt);
-
- // Make all the builtin named types used for type descriptors, and
- // then convert them. They will only be written out if they are
- // needed.
- Type::make_type_descriptor_type();
- Type::make_type_descriptor_ptr_type();
- Function_type::make_function_type_descriptor_type();
- Pointer_type::make_pointer_type_descriptor_type();
- Struct_type::make_struct_type_descriptor_type();
- Array_type::make_array_type_descriptor_type();
- Array_type::make_slice_type_descriptor_type();
- Map_type::make_map_type_descriptor_type();
- Map_type::make_map_descriptor_type();
- Channel_type::make_chan_type_descriptor_type();
- Interface_type::make_interface_type_descriptor_type();
- Type::convert_builtin_named_types(this);
-
- Runtime::convert_types(this);
-
- this->named_types_are_converted_ = true;
-}
-
-// Convert all names types in a set of bindings.
-
-void
-Gogo::convert_named_types_in_bindings(Bindings* bindings)
-{
- for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
- p != bindings->end_definitions();
- ++p)
- {
- if ((*p)->is_type())
- (*p)->type_value()->convert(this);
- }
-}
-
-// Class Function.
-
-Function::Function(Function_type* type, Function* enclosing, Block* block,
- Location location)
- : type_(type), enclosing_(enclosing), results_(NULL),
- closure_var_(NULL), block_(block), location_(location), labels_(),
- local_type_count_(0), fndecl_(NULL), defer_stack_(NULL),
- results_are_named_(false), nointerface_(false), calls_recover_(false),
- is_recover_thunk_(false), has_recover_thunk_(false),
- in_unique_section_(false)
-{
-}
-
-// Create the named result variables.
-
-void
-Function::create_result_variables(Gogo* gogo)
-{
- const Typed_identifier_list* results = this->type_->results();
- if (results == NULL || results->empty())
- return;
-
- if (!results->front().name().empty())
- this->results_are_named_ = true;
-
- this->results_ = new Results();
- this->results_->reserve(results->size());
-
- Block* block = this->block_;
- int index = 0;
- for (Typed_identifier_list::const_iterator p = results->begin();
- p != results->end();
- ++p, ++index)
- {
- std::string name = p->name();
- if (name.empty() || Gogo::is_sink_name(name))
- {
- static int result_counter;
- char buf[100];
- snprintf(buf, sizeof buf, "$ret%d", result_counter);
- ++result_counter;
- name = gogo->pack_hidden_name(buf, false);
- }
- Result_variable* result = new Result_variable(p->type(), this, index,
- p->location());
- Named_object* no = block->bindings()->add_result_variable(name, result);
- if (no->is_result_variable())
- this->results_->push_back(no);
- else
- {
- static int dummy_result_count;
- char buf[100];
- snprintf(buf, sizeof buf, "$dret%d", dummy_result_count);
- ++dummy_result_count;
- name = gogo->pack_hidden_name(buf, false);
- no = block->bindings()->add_result_variable(name, result);
- go_assert(no->is_result_variable());
- this->results_->push_back(no);
- }
- }
-}
-
-// Update the named result variables when cloning a function which
-// calls recover.
-
-void
-Function::update_result_variables()
-{
- if (this->results_ == NULL)
- return;
-
- for (Results::iterator p = this->results_->begin();
- p != this->results_->end();
- ++p)
- (*p)->result_var_value()->set_function(this);
-}
-
-// Return the closure variable, creating it if necessary.
-
-Named_object*
-Function::closure_var()
-{
- if (this->closure_var_ == NULL)
- {
- // We don't know the type of the variable yet. We add fields as
- // we find them.
- Location loc = this->type_->location();
- Struct_field_list* sfl = new Struct_field_list;
- Type* struct_type = Type::make_struct_type(sfl, loc);
- Variable* var = new Variable(Type::make_pointer_type(struct_type),
- NULL, false, true, false, loc);
- var->set_is_used();
- this->closure_var_ = Named_object::make_variable("closure", NULL, var);
- // Note that the new variable is not in any binding contour.
- }
- return this->closure_var_;
-}
-
-// Set the type of the closure variable.
-
-void
-Function::set_closure_type()
-{
- if (this->closure_var_ == NULL)
- return;
- Named_object* closure = this->closure_var_;
- Struct_type* st = closure->var_value()->type()->deref()->struct_type();
- unsigned int index = 0;
- for (Closure_fields::const_iterator p = this->closure_fields_.begin();
- p != this->closure_fields_.end();
- ++p, ++index)
- {
- Named_object* no = p->first;
- char buf[20];
- snprintf(buf, sizeof buf, "%u", index);
- std::string n = no->name() + buf;
- Type* var_type;
- if (no->is_variable())
- var_type = no->var_value()->type();
- else
- var_type = no->result_var_value()->type();
- Type* field_type = Type::make_pointer_type(var_type);
- st->push_field(Struct_field(Typed_identifier(n, field_type, p->second)));
- }
-}
-
-// Return whether this function is a method.
-
-bool
-Function::is_method() const
-{
- return this->type_->is_method();
-}
-
-// Add a label definition.
-
-Label*
-Function::add_label_definition(Gogo* gogo, const std::string& label_name,
- Location location)
-{
- Label* lnull = NULL;
- std::pair<Labels::iterator, bool> ins =
- this->labels_.insert(std::make_pair(label_name, lnull));
- Label* label;
- if (ins.second)
- {
- // This is a new label.
- label = new Label(label_name);
- ins.first->second = label;
- }
- else
- {
- // The label was already in the hash table.
- label = ins.first->second;
- if (label->is_defined())
- {
- error_at(location, "label %qs already defined",
- Gogo::message_name(label_name).c_str());
- inform(label->location(), "previous definition of %qs was here",
- Gogo::message_name(label_name).c_str());
- return new Label(label_name);
- }
- }
-
- label->define(location, gogo->bindings_snapshot(location));
-
- // Issue any errors appropriate for any previous goto's to this
- // label.
- const std::vector<Bindings_snapshot*>& refs(label->refs());
- for (std::vector<Bindings_snapshot*>::const_iterator p = refs.begin();
- p != refs.end();
- ++p)
- (*p)->check_goto_to(gogo->current_block());
- label->clear_refs();
-
- return label;
-}
-
-// Add a reference to a label.
-
-Label*
-Function::add_label_reference(Gogo* gogo, const std::string& label_name,
- Location location, bool issue_goto_errors)
-{
- Label* lnull = NULL;
- std::pair<Labels::iterator, bool> ins =
- this->labels_.insert(std::make_pair(label_name, lnull));
- Label* label;
- if (!ins.second)
- {
- // The label was already in the hash table.
- label = ins.first->second;
- }
- else
- {
- go_assert(ins.first->second == NULL);
- label = new Label(label_name);
- ins.first->second = label;
- }
-
- label->set_is_used();
-
- if (issue_goto_errors)
- {
- Bindings_snapshot* snapshot = label->snapshot();
- if (snapshot != NULL)
- snapshot->check_goto_from(gogo->current_block(), location);
- else
- label->add_snapshot_ref(gogo->bindings_snapshot(location));
- }
-
- return label;
-}
-
-// Warn about labels that are defined but not used.
-
-void
-Function::check_labels() const
-{
- for (Labels::const_iterator p = this->labels_.begin();
- p != this->labels_.end();
- p++)
- {
- Label* label = p->second;
- if (!label->is_used())
- error_at(label->location(), "label %qs defined and not used",
- Gogo::message_name(label->name()).c_str());
- }
-}
-
-// Swap one function with another. This is used when building the
-// thunk we use to call a function which calls recover. It may not
-// work for any other case.
-
-void
-Function::swap_for_recover(Function *x)
-{
- go_assert(this->enclosing_ == x->enclosing_);
- std::swap(this->results_, x->results_);
- std::swap(this->closure_var_, x->closure_var_);
- std::swap(this->block_, x->block_);
- go_assert(this->location_ == x->location_);
- go_assert(this->fndecl_ == NULL && x->fndecl_ == NULL);
- go_assert(this->defer_stack_ == NULL && x->defer_stack_ == NULL);
-}
-
-// Traverse the tree.
-
-int
-Function::traverse(Traverse* traverse)
-{
- unsigned int traverse_mask = traverse->traverse_mask();
-
- if ((traverse_mask
- & (Traverse::traverse_types | Traverse::traverse_expressions))
- != 0)
- {
- if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
-
- // FIXME: We should check traverse_functions here if nested
- // functions are stored in block bindings.
- if (this->block_ != NULL
- && (traverse_mask
- & (Traverse::traverse_variables
- | Traverse::traverse_constants
- | Traverse::traverse_blocks
- | Traverse::traverse_statements
- | Traverse::traverse_expressions
- | Traverse::traverse_types)) != 0)
- {
- if (this->block_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
-
- return TRAVERSE_CONTINUE;
-}
-
-// Work out types for unspecified variables and constants.
-
-void
-Function::determine_types()
-{
- if (this->block_ != NULL)
- this->block_->determine_types();
-}
-
-// Get a pointer to the variable representing the defer stack for this
-// function, making it if necessary. The value of the variable is set
-// by the runtime routines to true if the function is returning,
-// rather than panicing through. A pointer to this variable is used
-// as a marker for the functions on the defer stack associated with
-// this function. A function-specific variable permits inlining a
-// function which uses defer.
-
-Expression*
-Function::defer_stack(Location location)
-{
- if (this->defer_stack_ == NULL)
- {
- Type* t = Type::lookup_bool_type();
- Expression* n = Expression::make_boolean(false, location);
- this->defer_stack_ = Statement::make_temporary(t, n, location);
- this->defer_stack_->set_is_address_taken();
- }
- Expression* ref = Expression::make_temporary_reference(this->defer_stack_,
- location);
- return Expression::make_unary(OPERATOR_AND, ref, location);
-}
-
-// Export the function.
-
-void
-Function::export_func(Export* exp, const std::string& name) const
-{
- Function::export_func_with_type(exp, name, this->type_);
-}
-
-// Export a function with a type.
-
-void
-Function::export_func_with_type(Export* exp, const std::string& name,
- const Function_type* fntype)
-{
- exp->write_c_string("func ");
-
- if (fntype->is_method())
- {
- exp->write_c_string("(");
- const Typed_identifier* receiver = fntype->receiver();
- exp->write_name(receiver->name());
- exp->write_c_string(" ");
- exp->write_type(receiver->type());
- exp->write_c_string(") ");
- }
-
- exp->write_string(name);
-
- exp->write_c_string(" (");
- const Typed_identifier_list* parameters = fntype->parameters();
- if (parameters != NULL)
- {
- bool is_varargs = fntype->is_varargs();
- bool first = true;
- for (Typed_identifier_list::const_iterator p = parameters->begin();
- p != parameters->end();
- ++p)
- {
- if (first)
- first = false;
- else
- exp->write_c_string(", ");
- exp->write_name(p->name());
- exp->write_c_string(" ");
- if (!is_varargs || p + 1 != parameters->end())
- exp->write_type(p->type());
- else
- {
- exp->write_c_string("...");
- exp->write_type(p->type()->array_type()->element_type());
- }
- }
- }
- exp->write_c_string(")");
-
- const Typed_identifier_list* results = fntype->results();
- if (results != NULL)
- {
- if (results->size() == 1 && results->begin()->name().empty())
- {
- exp->write_c_string(" ");
- exp->write_type(results->begin()->type());
- }
- else
- {
- exp->write_c_string(" (");
- bool first = true;
- for (Typed_identifier_list::const_iterator p = results->begin();
- p != results->end();
- ++p)
- {
- if (first)
- first = false;
- else
- exp->write_c_string(", ");
- exp->write_name(p->name());
- exp->write_c_string(" ");
- exp->write_type(p->type());
- }
- exp->write_c_string(")");
- }
- }
- exp->write_c_string(";\n");
-}
-
-// Import a function.
-
-void
-Function::import_func(Import* imp, std::string* pname,
- Typed_identifier** preceiver,
- Typed_identifier_list** pparameters,
- Typed_identifier_list** presults,
- bool* is_varargs)
-{
- imp->require_c_string("func ");
-
- *preceiver = NULL;
- if (imp->peek_char() == '(')
- {
- imp->require_c_string("(");
- std::string name = imp->read_name();
- imp->require_c_string(" ");
- Type* rtype = imp->read_type();
- *preceiver = new Typed_identifier(name, rtype, imp->location());
- imp->require_c_string(") ");
- }
-
- *pname = imp->read_identifier();
-
- Typed_identifier_list* parameters;
- *is_varargs = false;
- imp->require_c_string(" (");
- if (imp->peek_char() == ')')
- parameters = NULL;
- else
- {
- parameters = new Typed_identifier_list();
- while (true)
- {
- std::string name = imp->read_name();
- imp->require_c_string(" ");
-
- if (imp->match_c_string("..."))
- {
- imp->advance(3);
- *is_varargs = true;
- }
-
- Type* ptype = imp->read_type();
- if (*is_varargs)
- ptype = Type::make_array_type(ptype, NULL);
- parameters->push_back(Typed_identifier(name, ptype,
- imp->location()));
- if (imp->peek_char() != ',')
- break;
- go_assert(!*is_varargs);
- imp->require_c_string(", ");
- }
- }
- imp->require_c_string(")");
- *pparameters = parameters;
-
- Typed_identifier_list* results;
- if (imp->peek_char() != ' ')
- results = NULL;
- else
- {
- results = new Typed_identifier_list();
- imp->require_c_string(" ");
- if (imp->peek_char() != '(')
- {
- Type* rtype = imp->read_type();
- results->push_back(Typed_identifier("", rtype, imp->location()));
- }
- else
- {
- imp->require_c_string("(");
- while (true)
- {
- std::string name = imp->read_name();
- imp->require_c_string(" ");
- Type* rtype = imp->read_type();
- results->push_back(Typed_identifier(name, rtype,
- imp->location()));
- if (imp->peek_char() != ',')
- break;
- imp->require_c_string(", ");
- }
- imp->require_c_string(")");
- }
- }
- imp->require_c_string(";\n");
- *presults = results;
-}
-
-// Class Block.
-
-Block::Block(Block* enclosing, Location location)
- : enclosing_(enclosing), statements_(),
- bindings_(new Bindings(enclosing == NULL
- ? NULL
- : enclosing->bindings())),
- start_location_(location),
- end_location_(UNKNOWN_LOCATION)
-{
-}
-
-// Add a statement to a block.
-
-void
-Block::add_statement(Statement* statement)
-{
- this->statements_.push_back(statement);
-}
-
-// Add a statement to the front of a block. This is slow but is only
-// used for reference counts of parameters.
-
-void
-Block::add_statement_at_front(Statement* statement)
-{
- this->statements_.insert(this->statements_.begin(), statement);
-}
-
-// Replace a statement in a block.
-
-void
-Block::replace_statement(size_t index, Statement* s)
-{
- go_assert(index < this->statements_.size());
- this->statements_[index] = s;
-}
-
-// Add a statement before another statement.
-
-void
-Block::insert_statement_before(size_t index, Statement* s)
-{
- go_assert(index < this->statements_.size());
- this->statements_.insert(this->statements_.begin() + index, s);
-}
-
-// Add a statement after another statement.
-
-void
-Block::insert_statement_after(size_t index, Statement* s)
-{
- go_assert(index < this->statements_.size());
- this->statements_.insert(this->statements_.begin() + index + 1, s);
-}
-
-// Traverse the tree.
-
-int
-Block::traverse(Traverse* traverse)
-{
- unsigned int traverse_mask = traverse->traverse_mask();
-
- if ((traverse_mask & Traverse::traverse_blocks) != 0)
- {
- int t = traverse->block(this);
- if (t == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- else if (t == TRAVERSE_SKIP_COMPONENTS)
- return TRAVERSE_CONTINUE;
- }
-
- if ((traverse_mask
- & (Traverse::traverse_variables
- | Traverse::traverse_constants
- | Traverse::traverse_expressions
- | Traverse::traverse_types)) != 0)
- {
- const unsigned int e_or_t = (Traverse::traverse_expressions
- | Traverse::traverse_types);
- const unsigned int e_or_t_or_s = (e_or_t
- | Traverse::traverse_statements);
- for (Bindings::const_definitions_iterator pb =
- this->bindings_->begin_definitions();
- pb != this->bindings_->end_definitions();
- ++pb)
- {
- int t = TRAVERSE_CONTINUE;
- switch ((*pb)->classification())
- {
- case Named_object::NAMED_OBJECT_CONST:
- if ((traverse_mask & Traverse::traverse_constants) != 0)
- t = traverse->constant(*pb, false);
- if (t == TRAVERSE_CONTINUE
- && (traverse_mask & e_or_t) != 0)
- {
- Type* tc = (*pb)->const_value()->type();
- if (tc != NULL
- && Type::traverse(tc, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- t = (*pb)->const_value()->traverse_expression(traverse);
- }
- break;
-
- case Named_object::NAMED_OBJECT_VAR:
- case Named_object::NAMED_OBJECT_RESULT_VAR:
- if ((traverse_mask & Traverse::traverse_variables) != 0)
- t = traverse->variable(*pb);
- if (t == TRAVERSE_CONTINUE
- && (traverse_mask & e_or_t) != 0)
- {
- if ((*pb)->is_result_variable()
- || (*pb)->var_value()->has_type())
- {
- Type* tv = ((*pb)->is_variable()
- ? (*pb)->var_value()->type()
- : (*pb)->result_var_value()->type());
- if (tv != NULL
- && Type::traverse(tv, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- if (t == TRAVERSE_CONTINUE
- && (traverse_mask & e_or_t_or_s) != 0
- && (*pb)->is_variable())
- t = (*pb)->var_value()->traverse_expression(traverse,
- traverse_mask);
- break;
-
- case Named_object::NAMED_OBJECT_FUNC:
- case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
- go_unreachable();
-
- case Named_object::NAMED_OBJECT_TYPE:
- if ((traverse_mask & e_or_t) != 0)
- t = Type::traverse((*pb)->type_value(), traverse);
- break;
-
- case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
- case Named_object::NAMED_OBJECT_UNKNOWN:
- case Named_object::NAMED_OBJECT_ERRONEOUS:
- break;
-
- case Named_object::NAMED_OBJECT_PACKAGE:
- case Named_object::NAMED_OBJECT_SINK:
- go_unreachable();
-
- default:
- go_unreachable();
- }
-
- if (t == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
-
- // No point in checking traverse_mask here--if we got here we always
- // want to walk the statements. The traversal can insert new
- // statements before or after the current statement. Inserting
- // statements before the current statement requires updating I via
- // the pointer; those statements will not be traversed. Any new
- // statements inserted after the current statement will be traversed
- // in their turn.
- for (size_t i = 0; i < this->statements_.size(); ++i)
- {
- if (this->statements_[i]->traverse(this, &i, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
-
- return TRAVERSE_CONTINUE;
-}
-
-// Work out types for unspecified variables and constants.
-
-void
-Block::determine_types()
-{
- for (Bindings::const_definitions_iterator pb =
- this->bindings_->begin_definitions();
- pb != this->bindings_->end_definitions();
- ++pb)
- {
- if ((*pb)->is_variable())
- (*pb)->var_value()->determine_type();
- else if ((*pb)->is_const())
- (*pb)->const_value()->determine_type();
- }
-
- for (std::vector<Statement*>::const_iterator ps = this->statements_.begin();
- ps != this->statements_.end();
- ++ps)
- (*ps)->determine_types();
-}
-
-// Return true if the statements in this block may fall through.
-
-bool
-Block::may_fall_through() const
-{
- if (this->statements_.empty())
- return true;
- return this->statements_.back()->may_fall_through();
-}
-
-// Convert a block to the backend representation.
-
-Bblock*
-Block::get_backend(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
- Named_object* function = context->function();
- std::vector<Bvariable*> vars;
- vars.reserve(this->bindings_->size_definitions());
- for (Bindings::const_definitions_iterator pv =
- this->bindings_->begin_definitions();
- pv != this->bindings_->end_definitions();
- ++pv)
- {
- if ((*pv)->is_variable() && !(*pv)->var_value()->is_parameter())
- vars.push_back((*pv)->get_backend_variable(gogo, function));
- }
-
- // FIXME: Permitting FUNCTION to be NULL here is a temporary measure
- // until we have a proper representation of the init function.
- Bfunction* bfunction;
- if (function == NULL)
- bfunction = NULL;
- else
- bfunction = tree_to_function(function->func_value()->get_decl());
- Bblock* ret = context->backend()->block(bfunction, context->bblock(),
- vars, this->start_location_,
- this->end_location_);
-
- Translate_context subcontext(gogo, function, this, ret);
- std::vector<Bstatement*> bstatements;
- bstatements.reserve(this->statements_.size());
- for (std::vector<Statement*>::const_iterator p = this->statements_.begin();
- p != this->statements_.end();
- ++p)
- bstatements.push_back((*p)->get_backend(&subcontext));
-
- context->backend()->block_add_statements(ret, bstatements);
-
- return ret;
-}
-
-// Class Bindings_snapshot.
-
-Bindings_snapshot::Bindings_snapshot(const Block* b, Location location)
- : block_(b), counts_(), location_(location)
-{
- while (b != NULL)
- {
- this->counts_.push_back(b->bindings()->size_definitions());
- b = b->enclosing();
- }
-}
-
-// Report errors appropriate for a goto from B to this.
-
-void
-Bindings_snapshot::check_goto_from(const Block* b, Location loc)
-{
- size_t dummy;
- if (!this->check_goto_block(loc, b, this->block_, &dummy))
- return;
- this->check_goto_defs(loc, this->block_,
- this->block_->bindings()->size_definitions(),
- this->counts_[0]);
-}
-
-// Report errors appropriate for a goto from this to B.
-
-void
-Bindings_snapshot::check_goto_to(const Block* b)
-{
- size_t index;
- if (!this->check_goto_block(this->location_, this->block_, b, &index))
- return;
- this->check_goto_defs(this->location_, b, this->counts_[index],
- b->bindings()->size_definitions());
-}
-
-// Report errors appropriate for a goto at LOC from BFROM to BTO.
-// Return true if all is well, false if we reported an error. If this
-// returns true, it sets *PINDEX to the number of blocks BTO is above
-// BFROM.
-
-bool
-Bindings_snapshot::check_goto_block(Location loc, const Block* bfrom,
- const Block* bto, size_t* pindex)
-{
- // It is an error if BTO is not either BFROM or above BFROM.
- size_t index = 0;
- for (const Block* pb = bfrom; pb != bto; pb = pb->enclosing(), ++index)
- {
- if (pb == NULL)
- {
- error_at(loc, "goto jumps into block");
- inform(bto->start_location(), "goto target block starts here");
- return false;
- }
- }
- *pindex = index;
- return true;
-}
-
-// Report errors appropriate for a goto at LOC ending at BLOCK, where
-// CFROM is the number of names defined at the point of the goto and
-// CTO is the number of names defined at the point of the label.
-
-void
-Bindings_snapshot::check_goto_defs(Location loc, const Block* block,
- size_t cfrom, size_t cto)
-{
- if (cfrom < cto)
- {
- Bindings::const_definitions_iterator p =
- block->bindings()->begin_definitions();
- for (size_t i = 0; i < cfrom; ++i)
- {
- go_assert(p != block->bindings()->end_definitions());
- ++p;
- }
- go_assert(p != block->bindings()->end_definitions());
-
- std::string n = (*p)->message_name();
- error_at(loc, "goto jumps over declaration of %qs", n.c_str());
- inform((*p)->location(), "%qs defined here", n.c_str());
- }
-}
-
-// Class Variable.
-
-Variable::Variable(Type* type, Expression* init, bool is_global,
- bool is_parameter, bool is_receiver,
- Location location)
- : type_(type), init_(init), preinit_(NULL), location_(location),
- backend_(NULL), is_global_(is_global), is_parameter_(is_parameter),
- is_receiver_(is_receiver), is_varargs_parameter_(false), is_used_(false),
- is_address_taken_(false), is_non_escaping_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),
- determined_type_(false), in_unique_section_(false)
-{
- go_assert(type != NULL || init != NULL);
- go_assert(!is_parameter || init == NULL);
-}
-
-// Traverse the initializer expression.
-
-int
-Variable::traverse_expression(Traverse* traverse, unsigned int traverse_mask)
-{
- if (this->preinit_ != NULL)
- {
- if (this->preinit_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- if (this->init_ != NULL
- && ((traverse_mask
- & (Traverse::traverse_expressions | Traverse::traverse_types))
- != 0))
- {
- if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Lower the initialization expression after parsing is complete.
-
-void
-Variable::lower_init_expression(Gogo* gogo, Named_object* function,
- Statement_inserter* inserter)
-{
- Named_object* dep = gogo->var_depends_on(this);
- if (dep != NULL && dep->is_variable())
- dep->var_value()->lower_init_expression(gogo, function, inserter);
-
- 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;
-
- Statement_inserter global_inserter;
- if (this->is_global_)
- {
- global_inserter = Statement_inserter(gogo, this);
- inserter = &global_inserter;
- }
-
- gogo->lower_expression(function, inserter, &this->init_);
-
- this->seen_ = false;
-
- this->init_is_lowered_ = true;
- }
-}
-
-// Get the preinit block.
-
-Block*
-Variable::preinit_block(Gogo* gogo)
-{
- go_assert(this->is_global_);
- if (this->preinit_ == NULL)
- this->preinit_ = new Block(NULL, this->location());
-
- // If a global variable has a preinitialization statement, then we
- // need to have an initialization function.
- gogo->set_need_init_fn();
-
- return this->preinit_;
-}
-
-// Add a statement to be run before the initialization expression.
-
-void
-Variable::add_preinit_statement(Gogo* gogo, Statement* s)
-{
- Block* b = this->preinit_block(gogo);
- b->add_statement(s);
- b->set_end_location(s->location());
-}
-
-// Whether this variable has a type.
-
-bool
-Variable::has_type() const
-{
- if (this->type_ == NULL)
- return false;
-
- // A variable created in a type switch case nil does not actually
- // have a type yet. It will be changed to use the initializer's
- // type in determine_type.
- if (this->is_type_switch_var_
- && this->type_->is_nil_constant_as_type())
- return false;
-
- return true;
-}
-
-// In an assignment which sets a variable to a tuple of EXPR, return
-// the type of the first element of the tuple.
-
-Type*
-Variable::type_from_tuple(Expression* expr, bool report_error) const
-{
- if (expr->map_index_expression() != NULL)
- {
- Map_type* mt = expr->map_index_expression()->get_map_type();
- if (mt == NULL)
- return Type::make_error_type();
- return mt->val_type();
- }
- else if (expr->receive_expression() != NULL)
- {
- Expression* channel = expr->receive_expression()->channel();
- Type* channel_type = channel->type();
- if (channel_type->channel_type() == NULL)
- return Type::make_error_type();
- return channel_type->channel_type()->element_type();
- }
- else
- {
- if (report_error)
- error_at(this->location(), "invalid tuple definition");
- return Type::make_error_type();
- }
-}
-
-// Given EXPR used in a range clause, return either the index type or
-// the value type of the range, depending upon GET_INDEX_TYPE.
-
-Type*
-Variable::type_from_range(Expression* expr, bool get_index_type,
- bool report_error) const
-{
- Type* t = expr->type();
- if (t->array_type() != NULL
- || (t->points_to() != NULL
- && t->points_to()->array_type() != NULL
- && !t->points_to()->is_slice_type()))
- {
- if (get_index_type)
- return Type::lookup_integer_type("int");
- else
- return t->deref()->array_type()->element_type();
- }
- else if (t->is_string_type())
- {
- if (get_index_type)
- return Type::lookup_integer_type("int");
- else
- return Type::lookup_integer_type("int32");
- }
- else if (t->map_type() != NULL)
- {
- if (get_index_type)
- return t->map_type()->key_type();
- else
- return t->map_type()->val_type();
- }
- else if (t->channel_type() != NULL)
- {
- if (get_index_type)
- return t->channel_type()->element_type();
- else
- {
- if (report_error)
- error_at(this->location(),
- "invalid definition of value variable for channel range");
- return Type::make_error_type();
- }
- }
- else
- {
- if (report_error)
- error_at(this->location(), "invalid type for range clause");
- return Type::make_error_type();
- }
-}
-
-// EXPR should be a channel. Return the channel's element type.
-
-Type*
-Variable::type_from_chan_element(Expression* expr, bool report_error) const
-{
- Type* t = expr->type();
- if (t->channel_type() != NULL)
- return t->channel_type()->element_type();
- else
- {
- if (report_error)
- error_at(this->location(), "expected channel");
- return Type::make_error_type();
- }
-}
-
-// Return the type of the Variable. This may be called before
-// Variable::determine_type is called, which means that we may need to
-// get the type from the initializer. FIXME: If we combine lowering
-// with type determination, then this should be unnecessary.
-
-Type*
-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.
- Type* type = this->type_;
- Expression* init = this->init_;
- if (this->is_type_switch_var_
- && this->type_->is_nil_constant_as_type())
- {
- Type_guard_expression* tge = this->init_->type_guard_expression();
- go_assert(tge != NULL);
- init = tge->expr();
- 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)
- ;
- else if (this->type_from_init_tuple_)
- type = this->type_from_tuple(init, false);
- else if (this->type_from_range_index_ || this->type_from_range_value_)
- type = this->type_from_range(init, this->type_from_range_index_, false);
- else if (this->type_from_chan_element_)
- type = this->type_from_chan_element(init, false);
- else
- {
- go_assert(init != NULL);
- type = init->type();
- go_assert(type != NULL);
-
- // Variables should not have abstract types.
- if (type->is_abstract())
- type = type->make_non_abstract_type();
-
- if (type->is_void_type())
- type = Type::make_error_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
-{
- go_assert(this->type_ != NULL);
- return this->type_;
-}
-
-// Set the type if necessary.
-
-void
-Variable::determine_type()
-{
- if (this->determined_type_)
- return;
- this->determined_type_ = true;
-
- if (this->preinit_ != NULL)
- this->preinit_->determine_types();
-
- // A variable in a type switch with a nil case will have the wrong
- // type here. It will have an initializer which is a type guard.
- // We want to initialize it to the value without the type guard, and
- // use the type of that value as well.
- if (this->is_type_switch_var_ && this->type_->is_nil_constant_as_type())
- {
- Type_guard_expression* tge = this->init_->type_guard_expression();
- go_assert(tge != NULL);
- this->type_ = NULL;
- this->init_ = tge->expr();
- }
-
- if (this->init_ == NULL)
- go_assert(this->type_ != NULL && !this->type_->is_abstract());
- else if (this->type_from_init_tuple_)
- {
- Expression *init = this->init_;
- init->determine_type_no_context();
- this->type_ = this->type_from_tuple(init, true);
- this->init_ = NULL;
- }
- else if (this->type_from_range_index_ || this->type_from_range_value_)
- {
- Expression* init = this->init_;
- init->determine_type_no_context();
- this->type_ = this->type_from_range(init, this->type_from_range_index_,
- true);
- this->init_ = NULL;
- }
- else if (this->type_from_chan_element_)
- {
- Expression* init = this->init_;
- init->determine_type_no_context();
- this->type_ = this->type_from_chan_element(init, true);
- this->init_ = NULL;
- }
- else
- {
- Type_context context(this->type_, false);
- this->init_->determine_type(&context);
- if (this->type_ == NULL)
- {
- Type* type = this->init_->type();
- go_assert(type != NULL);
- if (type->is_abstract())
- type = type->make_non_abstract_type();
-
- if (type->is_void_type())
- {
- error_at(this->location_, "variable has no type");
- type = Type::make_error_type();
- }
- else if (type->is_nil_type())
- {
- error_at(this->location_, "variable defined to nil type");
- type = Type::make_error_type();
- }
- else if (type->is_call_multiple_result_type())
- {
- error_at(this->location_,
- "single variable set to multiple-value function call");
- type = Type::make_error_type();
- }
-
- this->type_ = type;
- }
- }
-}
-
-// Export the variable
-
-void
-Variable::export_var(Export* exp, const std::string& name) const
-{
- go_assert(this->is_global_);
- exp->write_c_string("var ");
- exp->write_string(name);
- exp->write_c_string(" ");
- exp->write_type(this->type());
- exp->write_c_string(";\n");
-}
-
-// Import a variable.
-
-void
-Variable::import_var(Import* imp, std::string* pname, Type** ptype)
-{
- imp->require_c_string("var ");
- *pname = imp->read_identifier();
- imp->require_c_string(" ");
- *ptype = imp->read_type();
- imp->require_c_string(";\n");
-}
-
-// Convert a variable to the backend representation.
-
-Bvariable*
-Variable::get_backend_variable(Gogo* gogo, Named_object* function,
- const Package* package, const std::string& name)
-{
- if (this->backend_ == NULL)
- {
- Backend* backend = gogo->backend();
- Type* type = this->type_;
- if (type->is_error_type()
- || (type->is_undefined()
- && (!this->is_global_ || package == NULL)))
- this->backend_ = backend->error_variable();
- else
- {
- bool is_parameter = this->is_parameter_;
- if (this->is_receiver_ && type->points_to() == NULL)
- is_parameter = false;
- if (this->is_in_heap())
- {
- is_parameter = false;
- type = Type::make_pointer_type(type);
- }
-
- std::string n = Gogo::unpack_hidden_name(name);
- Btype* btype = type->get_backend(gogo);
-
- Bvariable* bvar;
- if (this->is_global_)
- bvar = backend->global_variable((package == NULL
- ? gogo->package_name()
- : package->package_name()),
- (package == NULL
- ? gogo->pkgpath_symbol()
- : package->pkgpath_symbol()),
- n,
- btype,
- package != NULL,
- Gogo::is_hidden_name(name),
- this->in_unique_section_,
- this->location_);
- else if (function == NULL)
- {
- go_assert(saw_errors());
- bvar = backend->error_variable();
- }
- else
- {
- tree fndecl = function->func_value()->get_decl();
- Bfunction* bfunction = tree_to_function(fndecl);
- bool is_address_taken = (this->is_non_escaping_address_taken_
- && !this->is_in_heap());
- if (is_parameter)
- bvar = backend->parameter_variable(bfunction, n, btype,
- is_address_taken,
- this->location_);
- else
- bvar = backend->local_variable(bfunction, n, btype,
- is_address_taken,
- this->location_);
- }
- this->backend_ = bvar;
- }
- }
- return this->backend_;
-}
-
-// Class Result_variable.
-
-// Convert a result variable to the backend representation.
-
-Bvariable*
-Result_variable::get_backend_variable(Gogo* gogo, Named_object* function,
- const std::string& name)
-{
- if (this->backend_ == NULL)
- {
- Backend* backend = gogo->backend();
- Type* type = this->type_;
- if (type->is_error())
- this->backend_ = backend->error_variable();
- else
- {
- if (this->is_in_heap())
- type = Type::make_pointer_type(type);
- Btype* btype = type->get_backend(gogo);
- tree fndecl = function->func_value()->get_decl();
- Bfunction* bfunction = tree_to_function(fndecl);
- std::string n = Gogo::unpack_hidden_name(name);
- bool is_address_taken = (this->is_non_escaping_address_taken_
- && !this->is_in_heap());
- this->backend_ = backend->local_variable(bfunction, n, btype,
- is_address_taken,
- this->location_);
- }
- }
- return this->backend_;
-}
-
-// Class Named_constant.
-
-// Traverse the initializer expression.
-
-int
-Named_constant::traverse_expression(Traverse* traverse)
-{
- return Expression::traverse(&this->expr_, traverse);
-}
-
-// Determine the type of the constant.
-
-void
-Named_constant::determine_type()
-{
- if (this->type_ != NULL)
- {
- Type_context context(this->type_, false);
- this->expr_->determine_type(&context);
- }
- else
- {
- // A constant may have an abstract type.
- Type_context context(NULL, true);
- this->expr_->determine_type(&context);
- this->type_ = this->expr_->type();
- go_assert(this->type_ != NULL);
- }
-}
-
-// Indicate that we found and reported an error for this constant.
-
-void
-Named_constant::set_error()
-{
- this->type_ = Type::make_error_type();
- this->expr_ = Expression::make_error(this->location_);
-}
-
-// Export a constant.
-
-void
-Named_constant::export_const(Export* exp, const std::string& name) const
-{
- exp->write_c_string("const ");
- exp->write_string(name);
- exp->write_c_string(" ");
- if (!this->type_->is_abstract())
- {
- exp->write_type(this->type_);
- exp->write_c_string(" ");
- }
- exp->write_c_string("= ");
- this->expr()->export_expression(exp);
- exp->write_c_string(";\n");
-}
-
-// Import a constant.
-
-void
-Named_constant::import_const(Import* imp, std::string* pname, Type** ptype,
- Expression** pexpr)
-{
- imp->require_c_string("const ");
- *pname = imp->read_identifier();
- imp->require_c_string(" ");
- if (imp->peek_char() == '=')
- *ptype = NULL;
- else
- {
- *ptype = imp->read_type();
- imp->require_c_string(" ");
- }
- imp->require_c_string("= ");
- *pexpr = Expression::import_expression(imp);
- imp->require_c_string(";\n");
-}
-
-// Add a method.
-
-Named_object*
-Type_declaration::add_method(const std::string& name, Function* function)
-{
- Named_object* ret = Named_object::make_function(name, NULL, function);
- this->methods_.push_back(ret);
- return ret;
-}
-
-// Add a method declaration.
-
-Named_object*
-Type_declaration::add_method_declaration(const std::string& name,
- Package* package,
- Function_type* type,
- Location location)
-{
- Named_object* ret = Named_object::make_function_declaration(name, package,
- type, location);
- this->methods_.push_back(ret);
- return ret;
-}
-
-// Return whether any methods ere defined.
-
-bool
-Type_declaration::has_methods() const
-{
- return !this->methods_.empty();
-}
-
-// Define methods for the real type.
-
-void
-Type_declaration::define_methods(Named_type* nt)
-{
- for (std::vector<Named_object*>::const_iterator p = this->methods_.begin();
- p != this->methods_.end();
- ++p)
- nt->add_existing_method(*p);
-}
-
-// We are using the type. Return true if we should issue a warning.
-
-bool
-Type_declaration::using_type()
-{
- bool ret = !this->issued_warning_;
- this->issued_warning_ = true;
- return ret;
-}
-
-// Class Unknown_name.
-
-// Set the real named object.
-
-void
-Unknown_name::set_real_named_object(Named_object* no)
-{
- go_assert(this->real_named_object_ == NULL);
- go_assert(!no->is_unknown());
- this->real_named_object_ = no;
-}
-
-// Class Named_object.
-
-Named_object::Named_object(const std::string& name,
- const Package* package,
- Classification classification)
- : name_(name), package_(package), classification_(classification),
- tree_(NULL)
-{
- if (Gogo::is_sink_name(name))
- go_assert(classification == NAMED_OBJECT_SINK);
-}
-
-// Make an unknown name. This is used by the parser. The name must
-// be resolved later. Unknown names are only added in the current
-// package.
-
-Named_object*
-Named_object::make_unknown_name(const std::string& name,
- Location location)
-{
- Named_object* named_object = new Named_object(name, NULL,
- NAMED_OBJECT_UNKNOWN);
- Unknown_name* value = new Unknown_name(location);
- named_object->u_.unknown_value = value;
- return named_object;
-}
-
-// Make a constant.
-
-Named_object*
-Named_object::make_constant(const Typed_identifier& tid,
- const Package* package, Expression* expr,
- int iota_value)
-{
- Named_object* named_object = new Named_object(tid.name(), package,
- NAMED_OBJECT_CONST);
- Named_constant* named_constant = new Named_constant(tid.type(), expr,
- iota_value,
- tid.location());
- named_object->u_.const_value = named_constant;
- return named_object;
-}
-
-// Make a named type.
-
-Named_object*
-Named_object::make_type(const std::string& name, const Package* package,
- Type* type, Location location)
-{
- Named_object* named_object = new Named_object(name, package,
- NAMED_OBJECT_TYPE);
- Named_type* named_type = Type::make_named_type(named_object, type, location);
- named_object->u_.type_value = named_type;
- return named_object;
-}
-
-// Make a type declaration.
-
-Named_object*
-Named_object::make_type_declaration(const std::string& name,
- const Package* package,
- Location location)
-{
- Named_object* named_object = new Named_object(name, package,
- NAMED_OBJECT_TYPE_DECLARATION);
- Type_declaration* type_declaration = new Type_declaration(location);
- named_object->u_.type_declaration = type_declaration;
- return named_object;
-}
-
-// Make a variable.
-
-Named_object*
-Named_object::make_variable(const std::string& name, const Package* package,
- Variable* variable)
-{
- Named_object* named_object = new Named_object(name, package,
- NAMED_OBJECT_VAR);
- named_object->u_.var_value = variable;
- return named_object;
-}
-
-// Make a result variable.
-
-Named_object*
-Named_object::make_result_variable(const std::string& name,
- Result_variable* result)
-{
- Named_object* named_object = new Named_object(name, NULL,
- NAMED_OBJECT_RESULT_VAR);
- named_object->u_.result_var_value = result;
- return named_object;
-}
-
-// Make a sink. This is used for the special blank identifier _.
-
-Named_object*
-Named_object::make_sink()
-{
- return new Named_object("_", NULL, NAMED_OBJECT_SINK);
-}
-
-// Make a named function.
-
-Named_object*
-Named_object::make_function(const std::string& name, const Package* package,
- Function* function)
-{
- Named_object* named_object = new Named_object(name, package,
- NAMED_OBJECT_FUNC);
- named_object->u_.func_value = function;
- return named_object;
-}
-
-// Make a function declaration.
-
-Named_object*
-Named_object::make_function_declaration(const std::string& name,
- const Package* package,
- Function_type* fntype,
- Location location)
-{
- Named_object* named_object = new Named_object(name, package,
- NAMED_OBJECT_FUNC_DECLARATION);
- Function_declaration *func_decl = new Function_declaration(fntype, location);
- named_object->u_.func_declaration_value = func_decl;
- return named_object;
-}
-
-// Make a package.
-
-Named_object*
-Named_object::make_package(const std::string& alias, Package* package)
-{
- Named_object* named_object = new Named_object(alias, NULL,
- NAMED_OBJECT_PACKAGE);
- named_object->u_.package_value = package;
- return named_object;
-}
-
-// Return the name to use in an error message.
-
-std::string
-Named_object::message_name() const
-{
- if (this->package_ == NULL)
- return Gogo::message_name(this->name_);
- std::string ret;
- if (this->package_->has_package_name())
- ret = this->package_->package_name();
- else
- ret = this->package_->pkgpath();
- ret = Gogo::message_name(ret);
- ret += '.';
- ret += Gogo::message_name(this->name_);
- return ret;
-}
-
-// Set the type when a declaration is defined.
-
-void
-Named_object::set_type_value(Named_type* named_type)
-{
- go_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
- Type_declaration* td = this->u_.type_declaration;
- td->define_methods(named_type);
- unsigned int index;
- Named_object* in_function = td->in_function(&index);
- if (in_function != NULL)
- named_type->set_in_function(in_function, index);
- delete td;
- this->classification_ = NAMED_OBJECT_TYPE;
- this->u_.type_value = named_type;
-}
-
-// Define a function which was previously declared.
-
-void
-Named_object::set_function_value(Function* function)
-{
- go_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION);
- this->classification_ = NAMED_OBJECT_FUNC;
- // FIXME: We should free the old value.
- this->u_.func_value = function;
-}
-
-// Declare an unknown object as a type declaration.
-
-void
-Named_object::declare_as_type()
-{
- go_assert(this->classification_ == NAMED_OBJECT_UNKNOWN);
- Unknown_name* unk = this->u_.unknown_value;
- this->classification_ = NAMED_OBJECT_TYPE_DECLARATION;
- this->u_.type_declaration = new Type_declaration(unk->location());
- delete unk;
-}
-
-// Return the location of a named object.
-
-Location
-Named_object::location() const
-{
- switch (this->classification_)
- {
- default:
- case NAMED_OBJECT_UNINITIALIZED:
- go_unreachable();
-
- case NAMED_OBJECT_ERRONEOUS:
- return Linemap::unknown_location();
-
- case NAMED_OBJECT_UNKNOWN:
- return this->unknown_value()->location();
-
- case NAMED_OBJECT_CONST:
- return this->const_value()->location();
-
- case NAMED_OBJECT_TYPE:
- return this->type_value()->location();
-
- case NAMED_OBJECT_TYPE_DECLARATION:
- return this->type_declaration_value()->location();
-
- case NAMED_OBJECT_VAR:
- return this->var_value()->location();
-
- case NAMED_OBJECT_RESULT_VAR:
- return this->result_var_value()->location();
-
- case NAMED_OBJECT_SINK:
- go_unreachable();
-
- case NAMED_OBJECT_FUNC:
- return this->func_value()->location();
-
- case NAMED_OBJECT_FUNC_DECLARATION:
- return this->func_declaration_value()->location();
-
- case NAMED_OBJECT_PACKAGE:
- return this->package_value()->location();
- }
-}
-
-// Export a named object.
-
-void
-Named_object::export_named_object(Export* exp) const
-{
- switch (this->classification_)
- {
- default:
- case NAMED_OBJECT_UNINITIALIZED:
- case NAMED_OBJECT_UNKNOWN:
- go_unreachable();
-
- case NAMED_OBJECT_ERRONEOUS:
- break;
-
- case NAMED_OBJECT_CONST:
- this->const_value()->export_const(exp, this->name_);
- break;
-
- case NAMED_OBJECT_TYPE:
- this->type_value()->export_named_type(exp, this->name_);
- break;
-
- case NAMED_OBJECT_TYPE_DECLARATION:
- error_at(this->type_declaration_value()->location(),
- "attempt to export %<%s%> which was declared but not defined",
- this->message_name().c_str());
- break;
-
- case NAMED_OBJECT_FUNC_DECLARATION:
- this->func_declaration_value()->export_func(exp, this->name_);
- break;
-
- case NAMED_OBJECT_VAR:
- this->var_value()->export_var(exp, this->name_);
- break;
-
- case NAMED_OBJECT_RESULT_VAR:
- case NAMED_OBJECT_SINK:
- go_unreachable();
-
- case NAMED_OBJECT_FUNC:
- this->func_value()->export_func(exp, this->name_);
- break;
- }
-}
-
-// Convert a variable to the backend representation.
-
-Bvariable*
-Named_object::get_backend_variable(Gogo* gogo, Named_object* function)
-{
- if (this->classification_ == NAMED_OBJECT_VAR)
- return this->var_value()->get_backend_variable(gogo, function,
- this->package_, this->name_);
- else if (this->classification_ == NAMED_OBJECT_RESULT_VAR)
- return this->result_var_value()->get_backend_variable(gogo, function,
- this->name_);
- else
- go_unreachable();
-}
-
-// Class Bindings.
-
-Bindings::Bindings(Bindings* enclosing)
- : enclosing_(enclosing), named_objects_(), bindings_()
-{
-}
-
-// Clear imports.
-
-void
-Bindings::clear_file_scope(Gogo* gogo)
-{
- Contour::iterator p = this->bindings_.begin();
- while (p != this->bindings_.end())
- {
- bool keep;
- if (p->second->package() != NULL)
- keep = false;
- else if (p->second->is_package())
- keep = false;
- else if (p->second->is_function()
- && !p->second->func_value()->type()->is_method()
- && Gogo::unpack_hidden_name(p->second->name()) == "init")
- keep = false;
- else
- keep = true;
-
- if (keep)
- ++p;
- else
- {
- gogo->add_file_block_name(p->second->name(), p->second->location());
- p = this->bindings_.erase(p);
- }
- }
-}
-
-// Look up a symbol.
-
-Named_object*
-Bindings::lookup(const std::string& name) const
-{
- Contour::const_iterator p = this->bindings_.find(name);
- if (p != this->bindings_.end())
- return p->second->resolve();
- else if (this->enclosing_ != NULL)
- return this->enclosing_->lookup(name);
- else
- return NULL;
-}
-
-// Look up a symbol locally.
-
-Named_object*
-Bindings::lookup_local(const std::string& name) const
-{
- Contour::const_iterator p = this->bindings_.find(name);
- if (p == this->bindings_.end())
- return NULL;
- return p->second;
-}
-
-// Remove an object from a set of bindings. This is used for a
-// special case in thunks for functions which call recover.
-
-void
-Bindings::remove_binding(Named_object* no)
-{
- Contour::iterator pb = this->bindings_.find(no->name());
- go_assert(pb != this->bindings_.end());
- this->bindings_.erase(pb);
- for (std::vector<Named_object*>::iterator pn = this->named_objects_.begin();
- pn != this->named_objects_.end();
- ++pn)
- {
- if (*pn == no)
- {
- this->named_objects_.erase(pn);
- return;
- }
- }
- go_unreachable();
-}
-
-// Add a method to the list of objects. This is not added to the
-// lookup table. This is so that we have a single list of objects
-// declared at the top level, which we walk through when it's time to
-// convert to trees.
-
-void
-Bindings::add_method(Named_object* method)
-{
- this->named_objects_.push_back(method);
-}
-
-// Add a generic Named_object to a Contour.
-
-Named_object*
-Bindings::add_named_object_to_contour(Contour* contour,
- Named_object* named_object)
-{
- go_assert(named_object == named_object->resolve());
- const std::string& name(named_object->name());
- go_assert(!Gogo::is_sink_name(name));
-
- std::pair<Contour::iterator, bool> ins =
- contour->insert(std::make_pair(name, named_object));
- if (!ins.second)
- {
- // The name was already there.
- if (named_object->package() != NULL
- && ins.first->second->package() == named_object->package()
- && (ins.first->second->classification()
- == named_object->classification()))
- {
- // This is a second import of the same object.
- return ins.first->second;
- }
- ins.first->second = this->new_definition(ins.first->second,
- named_object);
- return ins.first->second;
- }
- else
- {
- // Don't push declarations on the list. We push them on when
- // and if we find the definitions. That way we genericize the
- // functions in order.
- if (!named_object->is_type_declaration()
- && !named_object->is_function_declaration()
- && !named_object->is_unknown())
- this->named_objects_.push_back(named_object);
- return named_object;
- }
-}
-
-// We had an existing named object OLD_OBJECT, and we've seen a new
-// one NEW_OBJECT with the same name. FIXME: This does not free the
-// new object when we don't need it.
-
-Named_object*
-Bindings::new_definition(Named_object* old_object, Named_object* new_object)
-{
- if (new_object->is_erroneous() && !old_object->is_erroneous())
- return new_object;
-
- std::string reason;
- switch (old_object->classification())
- {
- default:
- case Named_object::NAMED_OBJECT_UNINITIALIZED:
- go_unreachable();
-
- case Named_object::NAMED_OBJECT_ERRONEOUS:
- return old_object;
-
- case Named_object::NAMED_OBJECT_UNKNOWN:
- {
- Named_object* real = old_object->unknown_value()->real_named_object();
- if (real != NULL)
- return this->new_definition(real, new_object);
- go_assert(!new_object->is_unknown());
- old_object->unknown_value()->set_real_named_object(new_object);
- if (!new_object->is_type_declaration()
- && !new_object->is_function_declaration())
- this->named_objects_.push_back(new_object);
- return new_object;
- }
-
- case Named_object::NAMED_OBJECT_CONST:
- break;
-
- case Named_object::NAMED_OBJECT_TYPE:
- if (new_object->is_type_declaration())
- return old_object;
- break;
-
- case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
- if (new_object->is_type_declaration())
- return old_object;
- if (new_object->is_type())
- {
- old_object->set_type_value(new_object->type_value());
- new_object->type_value()->set_named_object(old_object);
- this->named_objects_.push_back(old_object);
- return old_object;
- }
- break;
-
- case Named_object::NAMED_OBJECT_VAR:
- case Named_object::NAMED_OBJECT_RESULT_VAR:
- // We have already given an error in the parser for cases where
- // one parameter or result variable redeclares another one.
- if ((new_object->is_variable()
- && new_object->var_value()->is_parameter())
- || new_object->is_result_variable())
- return old_object;
- break;
-
- case Named_object::NAMED_OBJECT_SINK:
- go_unreachable();
-
- case Named_object::NAMED_OBJECT_FUNC:
- if (new_object->is_function_declaration())
- {
- if (!new_object->func_declaration_value()->asm_name().empty())
- sorry("__asm__ for function definitions");
- Function_type* old_type = old_object->func_value()->type();
- Function_type* new_type =
- new_object->func_declaration_value()->type();
- if (old_type->is_valid_redeclaration(new_type, &reason))
- return old_object;
- }
- break;
-
- case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
- {
- Function_type* old_type = old_object->func_declaration_value()->type();
- if (new_object->is_function_declaration())
- {
- Function_type* new_type =
- new_object->func_declaration_value()->type();
- if (old_type->is_valid_redeclaration(new_type, &reason))
- return old_object;
- }
- if (new_object->is_function())
- {
- Function_type* new_type = new_object->func_value()->type();
- if (old_type->is_valid_redeclaration(new_type, &reason))
- {
- if (!old_object->func_declaration_value()->asm_name().empty())
- sorry("__asm__ for function definitions");
- old_object->set_function_value(new_object->func_value());
- this->named_objects_.push_back(old_object);
- return old_object;
- }
- }
- }
- break;
-
- case Named_object::NAMED_OBJECT_PACKAGE:
- break;
- }
-
- std::string n = old_object->message_name();
- if (reason.empty())
- error_at(new_object->location(), "redefinition of %qs", n.c_str());
- else
- error_at(new_object->location(), "redefinition of %qs: %s", n.c_str(),
- reason.c_str());
-
- inform(old_object->location(), "previous definition of %qs was here",
- n.c_str());
-
- return old_object;
-}
-
-// Add a named type.
-
-Named_object*
-Bindings::add_named_type(Named_type* named_type)
-{
- return this->add_named_object(named_type->named_object());
-}
-
-// Add a function.
-
-Named_object*
-Bindings::add_function(const std::string& name, const Package* package,
- Function* function)
-{
- return this->add_named_object(Named_object::make_function(name, package,
- function));
-}
-
-// Add a function declaration.
-
-Named_object*
-Bindings::add_function_declaration(const std::string& name,
- const Package* package,
- Function_type* type,
- Location location)
-{
- Named_object* no = Named_object::make_function_declaration(name, package,
- type, location);
- return this->add_named_object(no);
-}
-
-// Define a type which was previously declared.
-
-void
-Bindings::define_type(Named_object* no, Named_type* type)
-{
- no->set_type_value(type);
- this->named_objects_.push_back(no);
-}
-
-// Mark all local variables as used. This is used for some types of
-// parse error.
-
-void
-Bindings::mark_locals_used()
-{
- for (std::vector<Named_object*>::iterator p = this->named_objects_.begin();
- p != this->named_objects_.end();
- ++p)
- if ((*p)->is_variable())
- (*p)->var_value()->set_is_used();
-}
-
-// Traverse bindings.
-
-int
-Bindings::traverse(Traverse* traverse, bool is_global)
-{
- unsigned int traverse_mask = traverse->traverse_mask();
-
- // We don't use an iterator because we permit the traversal to add
- // new global objects.
- const unsigned int e_or_t = (Traverse::traverse_expressions
- | Traverse::traverse_types);
- const unsigned int e_or_t_or_s = (e_or_t
- | Traverse::traverse_statements);
- for (size_t i = 0; i < this->named_objects_.size(); ++i)
- {
- Named_object* p = this->named_objects_[i];
- int t = TRAVERSE_CONTINUE;
- switch (p->classification())
- {
- case Named_object::NAMED_OBJECT_CONST:
- if ((traverse_mask & Traverse::traverse_constants) != 0)
- t = traverse->constant(p, is_global);
- if (t == TRAVERSE_CONTINUE
- && (traverse_mask & e_or_t) != 0)
- {
- Type* tc = p->const_value()->type();
- if (tc != NULL
- && Type::traverse(tc, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- t = p->const_value()->traverse_expression(traverse);
- }
- break;
-
- case Named_object::NAMED_OBJECT_VAR:
- case Named_object::NAMED_OBJECT_RESULT_VAR:
- if ((traverse_mask & Traverse::traverse_variables) != 0)
- t = traverse->variable(p);
- if (t == TRAVERSE_CONTINUE
- && (traverse_mask & e_or_t) != 0)
- {
- if (p->is_result_variable()
- || p->var_value()->has_type())
- {
- Type* tv = (p->is_variable()
- ? p->var_value()->type()
- : p->result_var_value()->type());
- if (tv != NULL
- && Type::traverse(tv, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- if (t == TRAVERSE_CONTINUE
- && (traverse_mask & e_or_t_or_s) != 0
- && p->is_variable())
- t = p->var_value()->traverse_expression(traverse, traverse_mask);
- break;
-
- case Named_object::NAMED_OBJECT_FUNC:
- if ((traverse_mask & Traverse::traverse_functions) != 0)
- t = traverse->function(p);
-
- if (t == TRAVERSE_CONTINUE
- && (traverse_mask
- & (Traverse::traverse_variables
- | Traverse::traverse_constants
- | Traverse::traverse_functions
- | Traverse::traverse_blocks
- | Traverse::traverse_statements
- | Traverse::traverse_expressions
- | Traverse::traverse_types)) != 0)
- t = p->func_value()->traverse(traverse);
- break;
-
- case Named_object::NAMED_OBJECT_PACKAGE:
- // These are traversed in Gogo::traverse.
- go_assert(is_global);
- break;
-
- case Named_object::NAMED_OBJECT_TYPE:
- if ((traverse_mask & e_or_t) != 0)
- t = Type::traverse(p->type_value(), traverse);
- break;
-
- case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
- case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
- case Named_object::NAMED_OBJECT_UNKNOWN:
- case Named_object::NAMED_OBJECT_ERRONEOUS:
- break;
-
- case Named_object::NAMED_OBJECT_SINK:
- default:
- go_unreachable();
- }
-
- if (t == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
-
- // If we need to traverse types, check the function declarations,
- // which have types. Also check any methods of a type declaration.
- if ((traverse_mask & e_or_t) != 0)
- {
- for (Bindings::const_declarations_iterator p =
- this->begin_declarations();
- p != this->end_declarations();
- ++p)
- {
- if (p->second->is_function_declaration())
- {
- if (Type::traverse(p->second->func_declaration_value()->type(),
- traverse)
- == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- else if (p->second->is_type_declaration())
- {
- const std::vector<Named_object*>* methods =
- p->second->type_declaration_value()->methods();
- for (std::vector<Named_object*>::const_iterator pm =
- methods->begin();
- pm != methods->end();
- pm++)
- {
- Named_object* no = *pm;
- Type *t;
- if (no->is_function())
- t = no->func_value()->type();
- else if (no->is_function_declaration())
- t = no->func_declaration_value()->type();
- else
- continue;
- if (Type::traverse(t, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- }
- }
-
- return TRAVERSE_CONTINUE;
-}
-
-// Class Label.
-
-// Clear any references to this label.
-
-void
-Label::clear_refs()
-{
- for (std::vector<Bindings_snapshot*>::iterator p = this->refs_.begin();
- p != this->refs_.end();
- ++p)
- delete *p;
- this->refs_.clear();
-}
-
-// Get the backend representation for a label.
-
-Blabel*
-Label::get_backend_label(Translate_context* context)
-{
- if (this->blabel_ == NULL)
- {
- Function* function = context->function()->func_value();
- tree fndecl = function->get_decl();
- Bfunction* bfunction = tree_to_function(fndecl);
- this->blabel_ = context->backend()->label(bfunction, this->name_,
- this->location_);
- }
- return this->blabel_;
-}
-
-// Return an expression for the address of this label.
-
-Bexpression*
-Label::get_addr(Translate_context* context, Location location)
-{
- Blabel* label = this->get_backend_label(context);
- return context->backend()->label_address(label, location);
-}
-
-// Class Unnamed_label.
-
-// Get the backend representation for an unnamed label.
-
-Blabel*
-Unnamed_label::get_blabel(Translate_context* context)
-{
- if (this->blabel_ == NULL)
- {
- Function* function = context->function()->func_value();
- tree fndecl = function->get_decl();
- Bfunction* bfunction = tree_to_function(fndecl);
- this->blabel_ = context->backend()->label(bfunction, "",
- this->location_);
- }
- return this->blabel_;
-}
-
-// Return a statement which defines this unnamed label.
-
-Bstatement*
-Unnamed_label::get_definition(Translate_context* context)
-{
- Blabel* blabel = this->get_blabel(context);
- return context->backend()->label_definition_statement(blabel);
-}
-
-// Return a goto statement to this unnamed label.
-
-Bstatement*
-Unnamed_label::get_goto(Translate_context* context, Location location)
-{
- Blabel* blabel = this->get_blabel(context);
- return context->backend()->goto_statement(blabel, location);
-}
-
-// Class Package.
-
-Package::Package(const std::string& pkgpath, Location location)
- : pkgpath_(pkgpath), pkgpath_symbol_(Gogo::pkgpath_for_symbol(pkgpath)),
- package_name_(), bindings_(new Bindings(NULL)), priority_(0),
- location_(location), used_(false), is_imported_(false),
- uses_sink_alias_(false)
-{
- go_assert(!pkgpath.empty());
-
-}
-
-// Set the package name.
-
-void
-Package::set_package_name(const std::string& package_name, Location location)
-{
- go_assert(!package_name.empty());
- if (this->package_name_.empty())
- this->package_name_ = package_name;
- else if (this->package_name_ != package_name)
- error_at(location,
- "saw two different packages with the same package path %s: %s, %s",
- this->pkgpath_.c_str(), this->package_name_.c_str(),
- package_name.c_str());
-}
-
-// Set the priority. We may see multiple priorities for an imported
-// package; we want to use the largest one.
-
-void
-Package::set_priority(int priority)
-{
- if (priority > this->priority_)
- this->priority_ = priority;
-}
-
-// Determine types of constants. Everything else in a package
-// (variables, function declarations) should already have a fixed
-// type. Constants may have abstract types.
-
-void
-Package::determine_types()
-{
- Bindings* bindings = this->bindings_;
- for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
- p != bindings->end_definitions();
- ++p)
- {
- if ((*p)->is_const())
- (*p)->const_value()->determine_type();
- }
-}
-
-// Class Traverse.
-
-// Destructor.
-
-Traverse::~Traverse()
-{
- if (this->types_seen_ != NULL)
- delete this->types_seen_;
- if (this->expressions_seen_ != NULL)
- delete this->expressions_seen_;
-}
-
-// Record that we are looking at a type, and return true if we have
-// already seen it.
-
-bool
-Traverse::remember_type(const Type* type)
-{
- if (type->is_error_type())
- return true;
- go_assert((this->traverse_mask() & traverse_types) != 0
- || (this->traverse_mask() & traverse_expressions) != 0);
- // We mostly only have to remember named types. But it turns out
- // that an interface type can refer to itself without using a name
- // by relying on interface inheritance, as in
- // type I interface { F() interface{I} }
- if (type->classification() != Type::TYPE_NAMED
- && type->classification() != Type::TYPE_INTERFACE)
- return false;
- if (this->types_seen_ == NULL)
- this->types_seen_ = new Types_seen();
- std::pair<Types_seen::iterator, bool> ins = this->types_seen_->insert(type);
- return !ins.second;
-}
-
-// Record that we are looking at an expression, and return true if we
-// have already seen it.
-
-bool
-Traverse::remember_expression(const Expression* expression)
-{
- go_assert((this->traverse_mask() & traverse_types) != 0
- || (this->traverse_mask() & traverse_expressions) != 0);
- if (this->expressions_seen_ == NULL)
- this->expressions_seen_ = new Expressions_seen();
- std::pair<Expressions_seen::iterator, bool> ins =
- this->expressions_seen_->insert(expression);
- return !ins.second;
-}
-
-// The default versions of these functions should never be called: the
-// traversal mask indicates which functions may be called.
-
-int
-Traverse::variable(Named_object*)
-{
- go_unreachable();
-}
-
-int
-Traverse::constant(Named_object*, bool)
-{
- go_unreachable();
-}
-
-int
-Traverse::function(Named_object*)
-{
- go_unreachable();
-}
-
-int
-Traverse::block(Block*)
-{
- go_unreachable();
-}
-
-int
-Traverse::statement(Block*, size_t*, Statement*)
-{
- go_unreachable();
-}
-
-int
-Traverse::expression(Expression**)
-{
- go_unreachable();
-}
-
-int
-Traverse::type(Type*)
-{
- go_unreachable();
-}
-
-// Class Statement_inserter.
-
-void
-Statement_inserter::insert(Statement* s)
-{
- if (this->block_ != NULL)
- {
- go_assert(this->pindex_ != NULL);
- this->block_->insert_statement_before(*this->pindex_, s);
- ++*this->pindex_;
- }
- else if (this->var_ != NULL)
- this->var_->add_preinit_statement(this->gogo_, s);
- else
- go_assert(saw_errors());
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/gogo.h b/gcc-4.8.1/gcc/go/gofrontend/gogo.h
deleted file mode 100644
index f96ffcdfd..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/gogo.h
+++ /dev/null
@@ -1,2939 +0,0 @@
-// gogo.h -- Go frontend parsed representation. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_GOGO_H
-#define GO_GOGO_H
-
-#include "go-linemap.h"
-
-class Traverse;
-class Statement_inserter;
-class Type;
-class Type_hash_identical;
-class Type_equal;
-class Type_identical;
-class Typed_identifier;
-class Typed_identifier_list;
-class Function_type;
-class Expression;
-class Statement;
-class Temporary_statement;
-class Block;
-class Function;
-class Bindings;
-class Bindings_snapshot;
-class Package;
-class Variable;
-class Pointer_type;
-class Struct_type;
-class Struct_field;
-class Struct_field_list;
-class Array_type;
-class Map_type;
-class Channel_type;
-class Interface_type;
-class Named_type;
-class Forward_declaration_type;
-class Named_object;
-class Label;
-class Translate_context;
-class Backend;
-class Export;
-class Import;
-class Bexpression;
-class Bstatement;
-class Bblock;
-class Bvariable;
-class Blabel;
-
-// This file declares the basic classes used to hold the internal
-// representation of Go which is built by the parser.
-
-// An initialization function for an imported package. This is a
-// magic function which initializes variables and runs the "init"
-// function.
-
-class Import_init
-{
- public:
- Import_init(const std::string& package_name, const std::string& init_name,
- int priority)
- : package_name_(package_name), init_name_(init_name), priority_(priority)
- { }
-
- // The name of the package being imported.
- const std::string&
- package_name() const
- { return this->package_name_; }
-
- // The name of the package's init function.
- const std::string&
- init_name() const
- { return this->init_name_; }
-
- // The priority of the initialization function. Functions with a
- // lower priority number must be run first.
- int
- priority() const
- { return this->priority_; }
-
- private:
- // The name of the package being imported.
- std::string package_name_;
- // The name of the package's init function.
- std::string init_name_;
- // The priority.
- int priority_;
-};
-
-// For sorting purposes.
-
-inline bool
-operator<(const Import_init& i1, const Import_init& i2)
-{
- if (i1.priority() < i2.priority())
- return true;
- if (i1.priority() > i2.priority())
- return false;
- if (i1.package_name() != i2.package_name())
- return i1.package_name() < i2.package_name();
- return i1.init_name() < i2.init_name();
-}
-
-// The holder for the internal representation of the entire
-// compilation unit.
-
-class Gogo
-{
- public:
- // Create the IR, passing in the sizes of the types "int" and
- // "uintptr" in bits.
- Gogo(Backend* backend, Linemap *linemap, int int_type_size, int pointer_size);
-
- // Get the backend generator.
- Backend*
- backend()
- { return this->backend_; }
-
- // Get the Location generator.
- Linemap*
- linemap()
- { return this->linemap_; }
-
- // Get the package name.
- const std::string&
- package_name() const;
-
- // Set the package name.
- void
- set_package_name(const std::string&, Location);
-
- // Return whether this is the "main" package.
- bool
- is_main_package() const;
-
- // If necessary, adjust the name to use for a hidden symbol. We add
- // the package name, so that hidden symbols in different packages do
- // not collide.
- std::string
- pack_hidden_name(const std::string& name, bool is_exported) const
- {
- return (is_exported
- ? name
- : '.' + this->pkgpath() + '.' + name);
- }
-
- // Unpack a name which may have been hidden. Returns the
- // user-visible name of the object.
- static std::string
- unpack_hidden_name(const std::string& name)
- { return name[0] != '.' ? name : name.substr(name.rfind('.') + 1); }
-
- // Return whether a possibly packed name is hidden.
- static bool
- is_hidden_name(const std::string& name)
- { return name[0] == '.'; }
-
- // Return the package path of a hidden name.
- static std::string
- hidden_name_pkgpath(const std::string& name)
- {
- go_assert(Gogo::is_hidden_name(name));
- return name.substr(1, name.rfind('.') - 1);
- }
-
- // Given a name which may or may not have been hidden, return the
- // name to use in an error message.
- static std::string
- message_name(const std::string& name);
-
- // Return whether a name is the blank identifier _.
- static bool
- is_sink_name(const std::string& name)
- {
- return (name[0] == '.'
- && name[name.length() - 1] == '_'
- && name[name.length() - 2] == '.');
- }
-
- // Convert a pkgpath into a string suitable for a symbol
- static std::string
- pkgpath_for_symbol(const std::string& pkgpath);
-
- // Return the package path to use for reflect.Type.PkgPath.
- const std::string&
- pkgpath() const;
-
- // Return the package path to use for a symbol name.
- const std::string&
- pkgpath_symbol() const;
-
- // Set the package path from a command line option.
- void
- set_pkgpath(const std::string&);
-
- // Set the prefix from a command line option.
- void
- set_prefix(const std::string&);
-
- // Return whether pkgpath was set from a command line option.
- bool
- pkgpath_from_option() const
- { return this->pkgpath_from_option_; }
-
- // Return the relative import path as set from the command line.
- // Returns an empty string if it was not set.
- const std::string&
- relative_import_path() const
- { return this->relative_import_path_; }
-
- // Set the relative import path from a command line option.
- void
- set_relative_import_path(const std::string& s)
- {this->relative_import_path_ = s; }
-
- // Return the priority to use for the package we are compiling.
- // This is two more than the largest priority of any package we
- // import.
- int
- package_priority() const;
-
- // Import a package. FILENAME is the file name argument, LOCAL_NAME
- // is the local name to give to the package. If LOCAL_NAME is empty
- // the declarations are added to the global scope.
- void
- import_package(const std::string& filename, const std::string& local_name,
- bool is_local_name_exported, Location);
-
- // Whether we are the global binding level.
- bool
- in_global_scope() const;
-
- // Look up a name in the current binding contours.
- Named_object*
- lookup(const std::string&, Named_object** pfunction) const;
-
- // Look up a name in the current block.
- Named_object*
- lookup_in_block(const std::string&) const;
-
- // Look up a name in the global namespace--the universal scope.
- Named_object*
- lookup_global(const char*) const;
-
- // Add a new imported package. REAL_NAME is the real name of the
- // package. ALIAS is the alias of the package; this may be the same
- // as REAL_NAME. This sets *PADD_TO_GLOBALS if symbols added to
- // this package should be added to the global namespace; this is
- // true if the alias is ".". LOCATION is the location of the import
- // statement. This returns the new package, or NULL on error.
- Package*
- add_imported_package(const std::string& real_name, const std::string& alias,
- bool is_alias_exported,
- const std::string& pkgpath,
- Location location,
- bool* padd_to_globals);
-
- // Register a package. This package may or may not be imported.
- // This returns the Package structure for the package, creating if
- // it necessary.
- Package*
- register_package(const std::string& pkgpath, Location);
-
- // Start compiling a function. ADD_METHOD_TO_TYPE is true if a
- // method function should be added to the type of its receiver.
- Named_object*
- start_function(const std::string& name, Function_type* type,
- bool add_method_to_type, Location);
-
- // Finish compiling a function.
- void
- finish_function(Location);
-
- // Return the current function.
- Named_object*
- current_function() const;
-
- // Return the current block.
- Block*
- current_block();
-
- // Start a new block. This is not initially associated with a
- // function.
- void
- start_block(Location);
-
- // Finish the current block and return it.
- Block*
- finish_block(Location);
-
- // Declare an erroneous name. This is used to avoid knock-on errors
- // after a parsing error.
- Named_object*
- add_erroneous_name(const std::string& name);
-
- // Declare an unknown name. This is used while parsing. The name
- // must be resolved by the end of the parse. Unknown names are
- // always added at the package level.
- Named_object*
- add_unknown_name(const std::string& name, Location);
-
- // Declare a function.
- Named_object*
- declare_function(const std::string&, Function_type*, Location);
-
- // Declare a function at the package level. This is used for
- // functions generated for a type.
- Named_object*
- declare_package_function(const std::string&, Function_type*, Location);
-
- // Add a label.
- Label*
- add_label_definition(const std::string&, Location);
-
- // Add a label reference. ISSUE_GOTO_ERRORS is true if we should
- // report errors for a goto from the current location to the label
- // location.
- Label*
- add_label_reference(const std::string&, Location,
- bool issue_goto_errors);
-
- // Return a snapshot of the current binding state.
- Bindings_snapshot*
- bindings_snapshot(Location);
-
- // Add a statement to the current block.
- void
- add_statement(Statement*);
-
- // Add a block to the current block.
- void
- add_block(Block*, Location);
-
- // Add a constant.
- Named_object*
- add_constant(const Typed_identifier&, Expression*, int iota_value);
-
- // Add a type.
- void
- add_type(const std::string&, Type*, Location);
-
- // Add a named type. This is used for builtin types, and to add an
- // imported type to the global scope.
- void
- add_named_type(Named_type*);
-
- // Declare a type.
- Named_object*
- declare_type(const std::string&, Location);
-
- // Declare a type at the package level. This is used when the
- // parser sees an unknown name where a type name is required.
- Named_object*
- declare_package_type(const std::string&, Location);
-
- // Define a type which was already declared.
- void
- define_type(Named_object*, Named_type*);
-
- // Add a variable.
- Named_object*
- add_variable(const std::string&, Variable*);
-
- // Add a sink--a reference to the blank identifier _.
- Named_object*
- add_sink();
-
- // Add a type which needs to be verified. This is used for sink
- // types, just to give appropriate error messages.
- void
- add_type_to_verify(Type* type);
-
- // Add a named object to the current namespace. This is used for
- // import . "package".
- void
- add_named_object(Named_object*);
-
- // Add an identifier to the list of names seen in the file block.
- void
- add_file_block_name(const std::string& name, Location location)
- { this->file_block_names_[name] = location; }
-
- // Mark all local variables in current bindings as used. This is
- // used when there is a parse error to avoid useless errors.
- void
- mark_locals_used();
-
- // Return a name to use for a thunk function. A thunk function is
- // one we create during the compilation, for a go statement or a
- // defer statement or a method expression.
- static std::string
- thunk_name();
-
- // Return whether an object is a thunk.
- static bool
- is_thunk(const Named_object*);
-
- // Note that we've seen an interface type. This is used to build
- // all required interface method tables.
- void
- record_interface_type(Interface_type*);
-
- // Note that we need an initialization function.
- void
- set_need_init_fn()
- { this->need_init_fn_ = true; }
-
- // Clear out all names in file scope. This is called when we start
- // parsing a new file.
- void
- clear_file_scope();
-
- // Record that VAR1 must be initialized after VAR2. This is used
- // when VAR2 does not appear in VAR1's INIT or PREINIT.
- void
- record_var_depends_on(Variable* var1, Named_object* var2)
- {
- go_assert(this->var_deps_.find(var1) == this->var_deps_.end());
- this->var_deps_[var1] = var2;
- }
-
- // Return the variable that VAR depends on, or NULL if none.
- Named_object*
- var_depends_on(Variable* var) const
- {
- Var_deps::const_iterator p = this->var_deps_.find(var);
- return p != this->var_deps_.end() ? p->second : NULL;
- }
-
- // Queue up a type-specific function to be written out. This is
- // used when a type-specific function is needed when not at the top
- // level.
- void
- queue_specific_type_function(Type* type, Named_type* name,
- const std::string& hash_name,
- Function_type* hash_fntype,
- const std::string& equal_name,
- Function_type* equal_fntype);
-
- // Write out queued specific type functions.
- void
- write_specific_type_functions();
-
- // Whether we are done writing out specific type functions.
- bool
- specific_type_functions_are_written() const
- { return this->specific_type_functions_are_written_; }
-
- // Traverse the tree. See the Traverse class.
- void
- traverse(Traverse*);
-
- // Define the predeclared global names.
- void
- define_global_names();
-
- // Verify and complete all types.
- void
- verify_types();
-
- // Lower the parse tree.
- void
- lower_parse_tree();
-
- // Lower all the statements in a block.
- void
- lower_block(Named_object* function, Block*);
-
- // Lower an expression.
- void
- lower_expression(Named_object* function, Statement_inserter*, Expression**);
-
- // Lower a constant.
- void
- lower_constant(Named_object*);
-
- // Finalize the method lists and build stub methods for named types.
- void
- finalize_methods();
-
- // Work out the types to use for unspecified variables and
- // constants.
- void
- determine_types();
-
- // Type check the program.
- void
- check_types();
-
- // Check the types in a single block. This is used for complicated
- // go statements.
- void
- check_types_in_block(Block*);
-
- // Check for return statements.
- void
- check_return_statements();
-
- // Do all exports.
- void
- do_exports();
-
- // Add an import control function for an imported package to the
- // list.
- void
- add_import_init_fn(const std::string& package_name,
- const std::string& init_name, int prio);
-
- // Turn short-cut operators (&&, ||) into explicit if statements.
- void
- remove_shortcuts();
-
- // Use temporary variables to force order of evaluation.
- void
- order_evaluations();
-
- // Build thunks for functions which call recover.
- void
- build_recover_thunks();
-
- // Simplify statements which might use thunks: go and defer
- // statements.
- void
- simplify_thunk_statements();
-
- // Dump AST if -fgo-dump-ast is set
- void
- dump_ast(const char* basename);
-
- // Convert named types to the backend representation.
- void
- convert_named_types();
-
- // Convert named types in a list of bindings.
- void
- convert_named_types_in_bindings(Bindings*);
-
- // True if named types have been converted to the backend
- // representation.
- bool
- named_types_are_converted() const
- { return this->named_types_are_converted_; }
-
- // Write out the global values.
- void
- write_globals();
-
- // Create trees for implicit builtin functions.
- void
- define_builtin_function_trees();
-
- // Build a call to a builtin function. PDECL should point to a NULL
- // initialized static pointer which will hold the fndecl. NAME is
- // the name of the function. NARGS is the number of arguments.
- // RETTYPE is the return type. It is followed by NARGS pairs of
- // type and argument (both trees).
- static tree
- call_builtin(tree* pdecl, Location, const char* name, int nargs,
- tree rettype, ...);
-
- // Build a call to the runtime error function.
- tree
- runtime_error(int code, Location);
-
- // Build a builtin struct with a list of fields.
- static tree
- builtin_struct(tree* ptype, const char* struct_name, tree struct_type,
- int nfields, ...);
-
- // Mark a function declaration as a builtin library function.
- static void
- mark_fndecl_as_builtin_library(tree fndecl);
-
- // Build a constructor for a slice. SLICE_TYPE_TREE is the type of
- // the slice. VALUES points to the values. COUNT is the size,
- // CAPACITY is the capacity. If CAPACITY is NULL, it is set to
- // COUNT.
- static tree
- slice_constructor(tree slice_type_tree, tree values, tree count,
- tree capacity);
-
- // Build required interface method tables.
- void
- build_interface_method_tables();
-
- // Build an interface method table for a type: a list of function
- // pointers, one for each interface method. This returns a decl.
- tree
- interface_method_table_for_type(const Interface_type*, Type*,
- bool is_pointer);
-
- // Return a tree which allocate SIZE bytes to hold values of type
- // TYPE.
- tree
- allocate_memory(Type *type, tree size, Location);
-
- // Return a type to use for pointer to const char.
- static tree
- const_char_pointer_type_tree();
-
- // Build a string constant with the right type.
- static tree
- string_constant_tree(const std::string&);
-
- // Build a Go string constant. This returns a pointer to the
- // constant.
- tree
- go_string_constant_tree(const std::string&);
-
- // Receive a value from a channel.
- static tree
- receive_from_channel(tree type_tree, tree type_descriptor_tree, tree channel,
- Location);
-
- // Make a trampoline which calls FNADDR passing CLOSURE.
- tree
- make_trampoline(tree fnaddr, tree closure, Location);
-
- private:
- // During parsing, we keep a stack of functions. Each function on
- // the stack is one that we are currently parsing. For each
- // function, we keep track of the current stack of blocks.
- struct Open_function
- {
- // The function.
- Named_object* function;
- // The stack of active blocks in the function.
- std::vector<Block*> blocks;
- };
-
- // The stack of functions.
- typedef std::vector<Open_function> Open_functions;
-
- // Set up the built-in unsafe package.
- void
- import_unsafe(const std::string&, bool is_exported, Location);
-
- // Return the current binding contour.
- Bindings*
- current_bindings();
-
- const Bindings*
- current_bindings() const;
-
- // Get the name of the magic initialization function.
- const std::string&
- get_init_fn_name();
-
- // Get the decl for the magic initialization function.
- tree
- initialization_function_decl();
-
- // Write the magic initialization function.
- void
- write_initialization_function(tree fndecl, tree init_stmt_list);
-
- // Initialize imported packages.
- void
- init_imports(tree*);
-
- // Register variables with the garbage collector.
- void
- register_gc_vars(const std::vector<Named_object*>&, tree*);
-
- // Build a pointer to a Go string constant. This returns a pointer
- // to the pointer.
- tree
- ptr_go_string_constant_tree(const std::string&);
-
- // Return the type of a trampoline.
- static tree
- trampoline_type_tree();
-
- // Type used to map import names to packages.
- typedef std::map<std::string, Package*> Imports;
-
- // Type used to map package names to packages.
- typedef std::map<std::string, Package*> Packages;
-
- // Type used to map variables to the function calls that set them.
- // This is used for initialization dependency analysis.
- typedef std::map<Variable*, Named_object*> Var_deps;
-
- // Type used to map identifiers in the file block to the location
- // where they were defined.
- typedef Unordered_map(std::string, Location) File_block_names;
-
- // Type used to queue writing a type specific function.
- struct Specific_type_function
- {
- Type* type;
- Named_type* name;
- std::string hash_name;
- Function_type* hash_fntype;
- std::string equal_name;
- Function_type* equal_fntype;
-
- Specific_type_function(Type* atype, Named_type* aname,
- const std::string& ahash_name,
- Function_type* ahash_fntype,
- const std::string& aequal_name,
- Function_type* aequal_fntype)
- : type(atype), name(aname), hash_name(ahash_name),
- hash_fntype(ahash_fntype), equal_name(aequal_name),
- equal_fntype(aequal_fntype)
- { }
- };
-
- // The backend generator.
- Backend* backend_;
- // The object used to keep track of file names and line numbers.
- Linemap* linemap_;
- // The package we are compiling.
- Package* package_;
- // The list of currently open functions during parsing.
- Open_functions functions_;
- // The global binding contour. This includes the builtin functions
- // and the package we are compiling.
- Bindings* globals_;
- // The list of names we have seen in the file block.
- File_block_names file_block_names_;
- // Mapping from import file names to packages.
- Imports imports_;
- // Whether the magic unsafe package was imported.
- bool imported_unsafe_;
- // Mapping from package names we have seen to packages. This does
- // not include the package we are compiling.
- Packages packages_;
- // The functions named "init", if there are any.
- std::vector<Named_object*> init_functions_;
- // A mapping from variables to the function calls that initialize
- // them, if it is not stored in the variable's init or preinit.
- // This is used for dependency analysis.
- Var_deps var_deps_;
- // Whether we need a magic initialization function.
- bool need_init_fn_;
- // The name of the magic initialization function.
- std::string init_fn_name_;
- // A list of import control variables for packages that we import.
- std::set<Import_init> imported_init_fns_;
- // The package path used for reflection data.
- std::string pkgpath_;
- // The package path to use for a symbol name.
- std::string pkgpath_symbol_;
- // The prefix to use for symbols, from the -fgo-prefix option.
- std::string prefix_;
- // Whether pkgpath_ has been set.
- bool pkgpath_set_;
- // Whether an explicit package path was set by -fgo-pkgpath.
- bool pkgpath_from_option_;
- // Whether an explicit prefix was set by -fgo-prefix.
- bool prefix_from_option_;
- // The relative import path, from the -fgo-relative-import-path
- // option.
- std::string relative_import_path_;
- // A list of types to verify.
- std::vector<Type*> verify_types_;
- // A list of interface types defined while parsing.
- std::vector<Interface_type*> interface_types_;
- // Type specific functions to write out.
- std::vector<Specific_type_function*> specific_type_functions_;
- // Whether we are done writing out specific type functions.
- bool specific_type_functions_are_written_;
- // Whether named types have been converted.
- bool named_types_are_converted_;
-};
-
-// A block of statements.
-
-class Block
-{
- public:
- Block(Block* enclosing, Location);
-
- // Return the enclosing block.
- const Block*
- enclosing() const
- { return this->enclosing_; }
-
- // Return the bindings of the block.
- Bindings*
- bindings()
- { return this->bindings_; }
-
- const Bindings*
- bindings() const
- { return this->bindings_; }
-
- // Look at the block's statements.
- const std::vector<Statement*>*
- statements() const
- { return &this->statements_; }
-
- // Return the start location. This is normally the location of the
- // left curly brace which starts the block.
- Location
- start_location() const
- { return this->start_location_; }
-
- // Return the end location. This is normally the location of the
- // right curly brace which ends the block.
- Location
- end_location() const
- { return this->end_location_; }
-
- // Add a statement to the block.
- void
- add_statement(Statement*);
-
- // Add a statement to the front of the block.
- void
- add_statement_at_front(Statement*);
-
- // Replace a statement in a block.
- void
- replace_statement(size_t index, Statement*);
-
- // Add a Statement before statement number INDEX.
- void
- insert_statement_before(size_t index, Statement*);
-
- // Add a Statement after statement number INDEX.
- void
- insert_statement_after(size_t index, Statement*);
-
- // Set the end location of the block.
- void
- set_end_location(Location location)
- { this->end_location_ = location; }
-
- // Traverse the tree.
- int
- traverse(Traverse*);
-
- // Set final types for unspecified variables and constants.
- void
- determine_types();
-
- // Return true if execution of this block may fall through to the
- // next block.
- bool
- may_fall_through() const;
-
- // Convert the block to the backend representation.
- Bblock*
- get_backend(Translate_context*);
-
- // Iterate over statements.
-
- typedef std::vector<Statement*>::iterator iterator;
-
- iterator
- begin()
- { return this->statements_.begin(); }
-
- iterator
- end()
- { return this->statements_.end(); }
-
- private:
- // Enclosing block.
- Block* enclosing_;
- // Statements in the block.
- std::vector<Statement*> statements_;
- // Binding contour.
- Bindings* bindings_;
- // Location of start of block.
- Location start_location_;
- // Location of end of block.
- Location end_location_;
-};
-
-// A function.
-
-class Function
-{
- public:
- Function(Function_type* type, Function*, Block*, Location);
-
- // Return the function's type.
- Function_type*
- type() const
- { return this->type_; }
-
- // Return the enclosing function if there is one.
- Function*
- enclosing()
- { return this->enclosing_; }
-
- // Set the enclosing function. This is used when building thunks
- // for functions which call recover.
- void
- set_enclosing(Function* enclosing)
- {
- go_assert(this->enclosing_ == NULL);
- this->enclosing_ = enclosing;
- }
-
- // The result variables.
- typedef std::vector<Named_object*> Results;
-
- // Create the result variables in the outer block.
- void
- create_result_variables(Gogo*);
-
- // Update the named result variables when cloning a function which
- // calls recover.
- void
- update_result_variables();
-
- // Return the result variables.
- Results*
- result_variables()
- { return this->results_; }
-
- // Whether the result variables have names.
- bool
- results_are_named() const
- { return this->results_are_named_; }
-
- // Whether this method should not be included in the type
- // descriptor.
- bool
- nointerface() const
- {
- go_assert(this->is_method());
- return this->nointerface_;
- }
-
- // Record that this method should not be included in the type
- // descriptor.
- void
- set_nointerface()
- {
- go_assert(this->is_method());
- this->nointerface_ = true;
- }
-
- // Add a new field to the closure variable.
- void
- add_closure_field(Named_object* var, Location loc)
- { this->closure_fields_.push_back(std::make_pair(var, loc)); }
-
- // Whether this function needs a closure.
- bool
- needs_closure() const
- { return !this->closure_fields_.empty(); }
-
- // Return the closure variable, creating it if necessary. This is
- // passed to the function as a static chain parameter.
- Named_object*
- closure_var();
-
- // Set the closure variable. This is used when building thunks for
- // functions which call recover.
- void
- set_closure_var(Named_object* v)
- {
- go_assert(this->closure_var_ == NULL);
- this->closure_var_ = v;
- }
-
- // Return the variable for a reference to field INDEX in the closure
- // variable.
- Named_object*
- enclosing_var(unsigned int index)
- {
- go_assert(index < this->closure_fields_.size());
- return closure_fields_[index].first;
- }
-
- // Set the type of the closure variable if there is one.
- void
- set_closure_type();
-
- // Get the block of statements associated with the function.
- Block*
- block() const
- { return this->block_; }
-
- // Get the location of the start of the function.
- Location
- location() const
- { return this->location_; }
-
- // Return whether this function is actually a method.
- bool
- is_method() const;
-
- // Add a label definition to the function.
- Label*
- add_label_definition(Gogo*, const std::string& label_name, Location);
-
- // Add a label reference to a function. ISSUE_GOTO_ERRORS is true
- // if we should report errors for a goto from the current location
- // to the label location.
- Label*
- add_label_reference(Gogo*, const std::string& label_name,
- Location, bool issue_goto_errors);
-
- // Warn about labels that are defined but not used.
- void
- check_labels() const;
-
- // Note that a new local type has been added. Return its index.
- unsigned int
- new_local_type_index()
- { return this->local_type_count_++; }
-
- // Whether this function calls the predeclared recover function.
- bool
- calls_recover() const
- { return this->calls_recover_; }
-
- // Record that this function calls the predeclared recover function.
- // This is set during the lowering pass.
- void
- set_calls_recover()
- { this->calls_recover_ = true; }
-
- // Whether this is a recover thunk function.
- bool
- is_recover_thunk() const
- { return this->is_recover_thunk_; }
-
- // Record that this is a thunk built for a function which calls
- // recover.
- void
- set_is_recover_thunk()
- { this->is_recover_thunk_ = true; }
-
- // Whether this function already has a recover thunk.
- bool
- has_recover_thunk() const
- { return this->has_recover_thunk_; }
-
- // Record that this function already has a recover thunk.
- void
- set_has_recover_thunk()
- { this->has_recover_thunk_ = true; }
-
- // Mark the function as going into a unique section.
- void
- set_in_unique_section()
- { this->in_unique_section_ = true; }
-
- // Swap with another function. Used only for the thunk which calls
- // recover.
- void
- swap_for_recover(Function *);
-
- // Traverse the tree.
- int
- traverse(Traverse*);
-
- // Determine types in the function.
- void
- determine_types();
-
- // Return the function's decl given an identifier.
- tree
- get_or_make_decl(Gogo*, Named_object*, tree id);
-
- // Return the function's decl after it has been built.
- tree
- get_decl() const
- {
- go_assert(this->fndecl_ != NULL);
- return this->fndecl_;
- }
-
- // Set the function decl to hold a tree of the function code.
- void
- build_tree(Gogo*, Named_object*);
-
- // Get the value to return when not explicitly specified. May also
- // add statements to execute first to STMT_LIST.
- tree
- return_value(Gogo*, Named_object*, Location, tree* stmt_list) const;
-
- // Get a tree for the variable holding the defer stack.
- Expression*
- defer_stack(Location);
-
- // Export the function.
- void
- export_func(Export*, const std::string& name) const;
-
- // Export a function with a type.
- static void
- export_func_with_type(Export*, const std::string& name,
- const Function_type*);
-
- // Import a function.
- static void
- import_func(Import*, std::string* pname, Typed_identifier** receiver,
- Typed_identifier_list** pparameters,
- Typed_identifier_list** presults, bool* is_varargs);
-
- private:
- // Type for mapping from label names to Label objects.
- typedef Unordered_map(std::string, Label*) Labels;
-
- tree
- make_receiver_parm_decl(Gogo*, Named_object*, tree);
-
- tree
- copy_parm_to_heap(Gogo*, Named_object*, tree);
-
- void
- build_defer_wrapper(Gogo*, Named_object*, tree*, tree*);
-
- typedef std::vector<std::pair<Named_object*,
- Location> > Closure_fields;
-
- // The function's type.
- Function_type* type_;
- // The enclosing function. This is NULL when there isn't one, which
- // is the normal case.
- Function* enclosing_;
- // The result variables, if any.
- Results* results_;
- // If there is a closure, this is the list of variables which appear
- // in the closure. This is created by the parser, and then resolved
- // to a real type when we lower parse trees.
- Closure_fields closure_fields_;
- // The closure variable, passed as a parameter using the static
- // chain parameter. Normally NULL.
- Named_object* closure_var_;
- // The outer block of statements in the function.
- Block* block_;
- // The source location of the start of the function.
- Location location_;
- // Labels defined or referenced in the function.
- Labels labels_;
- // The number of local types defined in this function.
- unsigned int local_type_count_;
- // The function decl.
- tree fndecl_;
- // The defer stack variable. A pointer to this variable is used to
- // distinguish the defer stack for one function from another. This
- // is NULL unless we actually need a defer stack.
- Temporary_statement* defer_stack_;
- // True if the result variables are named.
- bool results_are_named_;
- // True if this method should not be included in the type descriptor.
- bool nointerface_;
- // True if this function calls the predeclared recover function.
- bool calls_recover_;
- // True if this a thunk built for a function which calls recover.
- bool is_recover_thunk_;
- // True if this function already has a recover thunk.
- bool has_recover_thunk_;
- // True if this function should be put in a unique section. This is
- // turned on for field tracking.
- bool in_unique_section_ : 1;
-};
-
-// A snapshot of the current binding state.
-
-class Bindings_snapshot
-{
- public:
- Bindings_snapshot(const Block*, Location);
-
- // Report any errors appropriate for a goto from the current binding
- // state of B to this one.
- void
- check_goto_from(const Block* b, Location);
-
- // Report any errors appropriate for a goto from this binding state
- // to the current state of B.
- void
- check_goto_to(const Block* b);
-
- private:
- bool
- check_goto_block(Location, const Block*, const Block*, size_t*);
-
- void
- check_goto_defs(Location, const Block*, size_t, size_t);
-
- // The current block.
- const Block* block_;
- // The number of names currently defined in each open block.
- // Element 0 is this->block_, element 1 is
- // this->block_->enclosing(), etc.
- std::vector<size_t> counts_;
- // The location where this snapshot was taken.
- Location location_;
-};
-
-// A function declaration.
-
-class Function_declaration
-{
- public:
- Function_declaration(Function_type* fntype, Location location)
- : fntype_(fntype), location_(location), asm_name_(), fndecl_(NULL)
- { }
-
- Function_type*
- type() const
- { return this->fntype_; }
-
- Location
- location() const
- { return this->location_; }
-
- const std::string&
- asm_name() const
- { return this->asm_name_; }
-
- // Set the assembler name.
- void
- set_asm_name(const std::string& asm_name)
- { this->asm_name_ = asm_name; }
-
- // Return a decl for the function given an identifier.
- tree
- get_or_make_decl(Gogo*, Named_object*, tree id);
-
- // Export a function declaration.
- void
- export_func(Export* exp, const std::string& name) const
- { Function::export_func_with_type(exp, name, this->fntype_); }
-
- private:
- // The type of the function.
- Function_type* fntype_;
- // The location of the declaration.
- Location location_;
- // The assembler name: this is the name to use in references to the
- // function. This is normally empty.
- std::string asm_name_;
- // The function decl if needed.
- tree fndecl_;
-};
-
-// A variable.
-
-class Variable
-{
- public:
- Variable(Type*, Expression*, bool is_global, bool is_parameter,
- bool is_receiver, Location);
-
- // Get the type of the variable.
- Type*
- type();
-
- Type*
- type() const;
-
- // Return whether the type is defined yet.
- bool
- has_type() const;
-
- // Get the initial value.
- Expression*
- init() const
- { return this->init_; }
-
- // Return whether there are any preinit statements.
- bool
- has_pre_init() const
- { return this->preinit_ != NULL; }
-
- // Return the preinit statements if any.
- Block*
- preinit() const
- { return this->preinit_; }
-
- // Return whether this is a global variable.
- bool
- is_global() const
- { return this->is_global_; }
-
- // Return whether this is a function parameter.
- bool
- is_parameter() const
- { return this->is_parameter_; }
-
- // Return whether this is the receiver parameter of a method.
- bool
- is_receiver() const
- { return this->is_receiver_; }
-
- // Change this parameter to be a receiver. This is used when
- // creating the thunks created for functions which call recover.
- void
- set_is_receiver()
- {
- go_assert(this->is_parameter_);
- this->is_receiver_ = true;
- }
-
- // Change this parameter to not be a receiver. This is used when
- // creating the thunks created for functions which call recover.
- void
- set_is_not_receiver()
- {
- go_assert(this->is_parameter_);
- this->is_receiver_ = false;
- }
-
- // Return whether this is the varargs parameter of a function.
- bool
- is_varargs_parameter() const
- { return this->is_varargs_parameter_; }
-
- // Whether this variable's address is taken.
- bool
- is_address_taken() const
- { return this->is_address_taken_; }
-
- // Whether this variable should live in the heap.
- bool
- is_in_heap() const
- { return this->is_address_taken_ && !this->is_global_; }
-
- // Note that something takes the address of this variable.
- void
- set_address_taken()
- { this->is_address_taken_ = true; }
-
- // Return whether the address is taken but does not escape.
- bool
- is_non_escaping_address_taken() const
- { return this->is_non_escaping_address_taken_; }
-
- // Note that something takes the address of this variable such that
- // the address does not escape the function.
- void
- set_non_escaping_address_taken()
- { this->is_non_escaping_address_taken_ = true; }
-
- // Get the source location of the variable's declaration.
- Location
- location() const
- { return this->location_; }
-
- // Record that this is the varargs parameter of a function.
- void
- set_is_varargs_parameter()
- {
- go_assert(this->is_parameter_);
- this->is_varargs_parameter_ = true;
- }
-
- // Return whether the variable has been used.
- bool
- is_used() const
- { return this->is_used_; }
-
- // Mark that the variable has been used.
- void
- set_is_used()
- { this->is_used_ = true; }
-
- // Clear the initial value; used for error handling.
- void
- clear_init()
- { this->init_ = NULL; }
-
- // Set the initial value; used for converting shortcuts.
- void
- set_init(Expression* init)
- { this->init_ = init; }
-
- // Get the preinit block, a block of statements to be run before the
- // initialization expression.
- Block*
- preinit_block(Gogo*);
-
- // Add a statement to be run before the initialization expression.
- // This is only used for global variables.
- void
- add_preinit_statement(Gogo*, Statement*);
-
- // Lower the initialization expression after parsing is complete.
- void
- lower_init_expression(Gogo*, Named_object*, Statement_inserter*);
-
- // A special case: the init value is used only to determine the
- // type. This is used if the variable is defined using := with the
- // comma-ok form of a map index or a receive expression. The init
- // value is actually the map index expression or receive expression.
- // We use this because we may not know the right type at parse time.
- void
- set_type_from_init_tuple()
- { this->type_from_init_tuple_ = true; }
-
- // Another special case: the init value is used only to determine
- // the type. This is used if the variable is defined using := with
- // a range clause. The init value is the range expression. The
- // type of the variable is the index type of the range expression
- // (i.e., the first value returned by a range).
- void
- set_type_from_range_index()
- { this->type_from_range_index_ = true; }
-
- // Another special case: like set_type_from_range_index, but the
- // type is the value type of the range expression (i.e., the second
- // value returned by a range).
- void
- set_type_from_range_value()
- { this->type_from_range_value_ = true; }
-
- // Another special case: the init value is used only to determine
- // the type. This is used if the variable is defined using := with
- // a case in a select statement. The init value is the channel.
- // The type of the variable is the channel's element type.
- void
- set_type_from_chan_element()
- { this->type_from_chan_element_ = true; }
-
- // After we lower the select statement, we once again set the type
- // from the initialization expression.
- void
- clear_type_from_chan_element()
- {
- go_assert(this->type_from_chan_element_);
- this->type_from_chan_element_ = false;
- }
-
- // Note that this variable was created for a type switch clause.
- void
- set_is_type_switch_var()
- { this->is_type_switch_var_ = true; }
-
- // Mark the variable as going into a unique section.
- void
- set_in_unique_section()
- {
- go_assert(this->is_global_);
- this->in_unique_section_ = true;
- }
-
- // Traverse the initializer expression.
- int
- traverse_expression(Traverse*, unsigned int traverse_mask);
-
- // Determine the type of the variable if necessary.
- void
- determine_type();
-
- // Get the backend representation of the variable.
- Bvariable*
- get_backend_variable(Gogo*, Named_object*, const Package*,
- const std::string&);
-
- // Get the initial value of the variable as a tree. This may only
- // be called if has_pre_init() returns false.
- tree
- get_init_tree(Gogo*, Named_object* function);
-
- // Return a series of statements which sets the value of the
- // variable in DECL. This should only be called is has_pre_init()
- // returns true. DECL may be NULL for a sink variable.
- tree
- get_init_block(Gogo*, Named_object* function, tree decl);
-
- // Export the variable.
- void
- export_var(Export*, const std::string& name) const;
-
- // Import a variable.
- static void
- import_var(Import*, std::string* pname, Type** ptype);
-
- private:
- // The type of a tuple.
- Type*
- type_from_tuple(Expression*, bool) const;
-
- // The type of a range.
- Type*
- type_from_range(Expression*, bool, bool) const;
-
- // The element type of a channel.
- Type*
- type_from_chan_element(Expression*, bool) const;
-
- // The variable's type. This may be NULL if the type is set from
- // the expression.
- Type* type_;
- // The initial value. This may be NULL if the variable should be
- // initialized to the default value for the type.
- Expression* init_;
- // Statements to run before the init statement.
- Block* preinit_;
- // Location of variable definition.
- Location location_;
- // Backend representation.
- Bvariable* backend_;
- // Whether this is a global variable.
- bool is_global_ : 1;
- // Whether this is a function parameter.
- bool is_parameter_ : 1;
- // Whether this is the receiver parameter of a method.
- bool is_receiver_ : 1;
- // Whether this is the varargs parameter of a function.
- bool is_varargs_parameter_ : 1;
- // Whether this variable is ever referenced.
- bool is_used_ : 1;
- // Whether something takes the address of this variable. For a
- // local variable this implies that the variable has to be on the
- // heap.
- bool is_address_taken_ : 1;
- // Whether something takes the address of this variable such that
- // the address does not escape the function.
- bool is_non_escaping_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.
- bool type_from_init_tuple_ : 1;
- // True if init is a range clause and the type is the index type.
- bool type_from_range_index_ : 1;
- // True if init is a range clause and the type is the value type.
- bool type_from_range_value_ : 1;
- // True if init is a channel and the type is the channel's element type.
- bool type_from_chan_element_ : 1;
- // True if this is a variable created for a type switch case.
- bool is_type_switch_var_ : 1;
- // True if we have determined types.
- bool determined_type_ : 1;
- // True if this variable should be put in a unique section. This is
- // used for field tracking.
- bool in_unique_section_ : 1;
-};
-
-// A variable which is really the name for a function return value, or
-// part of one.
-
-class Result_variable
-{
- public:
- Result_variable(Type* type, Function* function, int index,
- Location location)
- : type_(type), function_(function), index_(index), location_(location),
- backend_(NULL), is_address_taken_(false),
- is_non_escaping_address_taken_(false)
- { }
-
- // Get the type of the result variable.
- Type*
- type() const
- { return this->type_; }
-
- // Get the function that this is associated with.
- Function*
- function() const
- { return this->function_; }
-
- // Index in the list of function results.
- int
- index() const
- { return this->index_; }
-
- // The location of the variable definition.
- Location
- location() const
- { return this->location_; }
-
- // Whether this variable's address is taken.
- bool
- is_address_taken() const
- { return this->is_address_taken_; }
-
- // Note that something takes the address of this variable.
- void
- set_address_taken()
- { this->is_address_taken_ = true; }
-
- // Return whether the address is taken but does not escape.
- bool
- is_non_escaping_address_taken() const
- { return this->is_non_escaping_address_taken_; }
-
- // Note that something takes the address of this variable such that
- // the address does not escape the function.
- void
- set_non_escaping_address_taken()
- { this->is_non_escaping_address_taken_ = true; }
-
- // Whether this variable should live in the heap.
- bool
- is_in_heap() const
- { return this->is_address_taken_; }
-
- // Set the function. This is used when cloning functions which call
- // recover.
- void
- set_function(Function* function)
- { this->function_ = function; }
-
- // Get the backend representation of the variable.
- Bvariable*
- get_backend_variable(Gogo*, Named_object*, const std::string&);
-
- private:
- // Type of result variable.
- Type* type_;
- // Function with which this is associated.
- Function* function_;
- // Index in list of results.
- int index_;
- // Where the result variable is defined.
- Location location_;
- // Backend representation.
- Bvariable* backend_;
- // Whether something takes the address of this variable.
- bool is_address_taken_;
- // Whether something takes the address of this variable such that
- // the address does not escape the function.
- bool is_non_escaping_address_taken_;
-};
-
-// The value we keep for a named constant. This lets us hold a type
-// and an expression.
-
-class Named_constant
-{
- public:
- Named_constant(Type* type, Expression* expr, int iota_value,
- Location location)
- : type_(type), expr_(expr), iota_value_(iota_value), location_(location),
- lowering_(false)
- { }
-
- Type*
- type() const
- { return this->type_; }
-
- Expression*
- expr() const
- { return this->expr_; }
-
- int
- iota_value() const
- { return this->iota_value_; }
-
- Location
- location() const
- { return this->location_; }
-
- // Whether we are lowering.
- bool
- lowering() const
- { return this->lowering_; }
-
- // Set that we are lowering.
- void
- set_lowering()
- { this->lowering_ = true; }
-
- // We are no longer lowering.
- void
- clear_lowering()
- { this->lowering_ = false; }
-
- // Traverse the expression.
- int
- traverse_expression(Traverse*);
-
- // Determine the type of the constant if necessary.
- void
- determine_type();
-
- // Indicate that we found and reported an error for this constant.
- void
- set_error();
-
- // Export the constant.
- void
- export_const(Export*, const std::string& name) const;
-
- // Import a constant.
- static void
- import_const(Import*, std::string*, Type**, Expression**);
-
- private:
- // The type of the constant.
- Type* type_;
- // The expression for the constant.
- Expression* expr_;
- // If the predeclared constant iota is used in EXPR_, this is the
- // value it will have. We do this because at parse time we don't
- // know whether the name "iota" will refer to the predeclared
- // constant or to something else. We put in the right value in when
- // we lower.
- int iota_value_;
- // The location of the definition.
- Location location_;
- // Whether we are currently lowering this constant.
- bool lowering_;
-};
-
-// A type declaration.
-
-class Type_declaration
-{
- public:
- Type_declaration(Location location)
- : location_(location), in_function_(NULL), in_function_index_(0),
- methods_(), issued_warning_(false)
- { }
-
- // Return the location.
- Location
- location() const
- { return this->location_; }
-
- // Return the function in which this type is declared. This will
- // return NULL for a type declared in global scope.
- Named_object*
- in_function(unsigned int* pindex)
- {
- *pindex = this->in_function_index_;
- return this->in_function_;
- }
-
- // Set the function in which this type is declared.
- void
- set_in_function(Named_object* f, unsigned int index)
- {
- this->in_function_ = f;
- this->in_function_index_ = index;
- }
-
- // Add a method to this type. This is used when methods are defined
- // before the type.
- Named_object*
- add_method(const std::string& name, Function* function);
-
- // Add a method declaration to this type.
- Named_object*
- add_method_declaration(const std::string& name, Package*,
- Function_type* type, Location location);
-
- // Return whether any methods were defined.
- bool
- has_methods() const;
-
- // Return the methods.
- const std::vector<Named_object*>*
- methods() const
- { return &this->methods_; }
-
- // Define methods when the real type is known.
- void
- define_methods(Named_type*);
-
- // This is called if we are trying to use this type. It returns
- // true if we should issue a warning.
- bool
- using_type();
-
- private:
- // The location of the type declaration.
- Location location_;
- // If this type is declared in a function, a pointer back to the
- // function in which it is defined.
- Named_object* in_function_;
- // The index of this type in IN_FUNCTION_.
- unsigned int in_function_index_;
- // Methods defined before the type is defined.
- std::vector<Named_object*> methods_;
- // True if we have issued a warning about a use of this type
- // declaration when it is undefined.
- bool issued_warning_;
-};
-
-// An unknown object. These are created by the parser for forward
-// references to names which have not been seen before. In a correct
-// program, these will always point to a real definition by the end of
-// the parse. Because they point to another Named_object, these may
-// only be referenced by Unknown_expression objects.
-
-class Unknown_name
-{
- public:
- Unknown_name(Location location)
- : location_(location), real_named_object_(NULL)
- { }
-
- // Return the location where this name was first seen.
- Location
- location() const
- { return this->location_; }
-
- // Return the real named object that this points to, or NULL if it
- // was never resolved.
- Named_object*
- real_named_object() const
- { return this->real_named_object_; }
-
- // Set the real named object that this points to.
- void
- set_real_named_object(Named_object* no);
-
- private:
- // The location where this name was first seen.
- Location location_;
- // The real named object when it is known.
- Named_object*
- real_named_object_;
-};
-
-// A named object named. This is the result of a declaration. We
-// don't use a superclass because they all have to be handled
-// differently.
-
-class Named_object
-{
- public:
- enum Classification
- {
- // An uninitialized Named_object. We should never see this.
- NAMED_OBJECT_UNINITIALIZED,
- // An erroneous name. This indicates a parse error, to avoid
- // later errors about undefined references.
- NAMED_OBJECT_ERRONEOUS,
- // An unknown name. This is used for forward references. In a
- // correct program, these will all be resolved by the end of the
- // parse.
- NAMED_OBJECT_UNKNOWN,
- // A const.
- NAMED_OBJECT_CONST,
- // A type.
- NAMED_OBJECT_TYPE,
- // A forward type declaration.
- NAMED_OBJECT_TYPE_DECLARATION,
- // A var.
- NAMED_OBJECT_VAR,
- // A result variable in a function.
- NAMED_OBJECT_RESULT_VAR,
- // The blank identifier--the special variable named _.
- NAMED_OBJECT_SINK,
- // A func.
- NAMED_OBJECT_FUNC,
- // A forward func declaration.
- NAMED_OBJECT_FUNC_DECLARATION,
- // A package.
- NAMED_OBJECT_PACKAGE
- };
-
- // Return the classification.
- Classification
- classification() const
- { return this->classification_; }
-
- // Classifiers.
-
- bool
- is_erroneous() const
- { return this->classification_ == NAMED_OBJECT_ERRONEOUS; }
-
- bool
- is_unknown() const
- { return this->classification_ == NAMED_OBJECT_UNKNOWN; }
-
- bool
- is_const() const
- { return this->classification_ == NAMED_OBJECT_CONST; }
-
- bool
- is_type() const
- { return this->classification_ == NAMED_OBJECT_TYPE; }
-
- bool
- is_type_declaration() const
- { return this->classification_ == NAMED_OBJECT_TYPE_DECLARATION; }
-
- bool
- is_variable() const
- { return this->classification_ == NAMED_OBJECT_VAR; }
-
- bool
- is_result_variable() const
- { return this->classification_ == NAMED_OBJECT_RESULT_VAR; }
-
- bool
- is_sink() const
- { return this->classification_ == NAMED_OBJECT_SINK; }
-
- bool
- is_function() const
- { return this->classification_ == NAMED_OBJECT_FUNC; }
-
- bool
- is_function_declaration() const
- { return this->classification_ == NAMED_OBJECT_FUNC_DECLARATION; }
-
- bool
- is_package() const
- { return this->classification_ == NAMED_OBJECT_PACKAGE; }
-
- // Creators.
-
- static Named_object*
- make_erroneous_name(const std::string& name)
- { return new Named_object(name, NULL, NAMED_OBJECT_ERRONEOUS); }
-
- static Named_object*
- make_unknown_name(const std::string& name, Location);
-
- static Named_object*
- make_constant(const Typed_identifier&, const Package*, Expression*,
- int iota_value);
-
- static Named_object*
- make_type(const std::string&, const Package*, Type*, Location);
-
- static Named_object*
- make_type_declaration(const std::string&, const Package*, Location);
-
- static Named_object*
- make_variable(const std::string&, const Package*, Variable*);
-
- static Named_object*
- make_result_variable(const std::string&, Result_variable*);
-
- static Named_object*
- make_sink();
-
- static Named_object*
- make_function(const std::string&, const Package*, Function*);
-
- static Named_object*
- make_function_declaration(const std::string&, const Package*, Function_type*,
- Location);
-
- static Named_object*
- make_package(const std::string& alias, Package* package);
-
- // Getters.
-
- Unknown_name*
- unknown_value()
- {
- go_assert(this->classification_ == NAMED_OBJECT_UNKNOWN);
- return this->u_.unknown_value;
- }
-
- const Unknown_name*
- unknown_value() const
- {
- go_assert(this->classification_ == NAMED_OBJECT_UNKNOWN);
- return this->u_.unknown_value;
- }
-
- Named_constant*
- const_value()
- {
- go_assert(this->classification_ == NAMED_OBJECT_CONST);
- return this->u_.const_value;
- }
-
- const Named_constant*
- const_value() const
- {
- go_assert(this->classification_ == NAMED_OBJECT_CONST);
- return this->u_.const_value;
- }
-
- Named_type*
- type_value()
- {
- go_assert(this->classification_ == NAMED_OBJECT_TYPE);
- return this->u_.type_value;
- }
-
- const Named_type*
- type_value() const
- {
- go_assert(this->classification_ == NAMED_OBJECT_TYPE);
- return this->u_.type_value;
- }
-
- Type_declaration*
- type_declaration_value()
- {
- go_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
- return this->u_.type_declaration;
- }
-
- const Type_declaration*
- type_declaration_value() const
- {
- go_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
- return this->u_.type_declaration;
- }
-
- Variable*
- var_value()
- {
- go_assert(this->classification_ == NAMED_OBJECT_VAR);
- return this->u_.var_value;
- }
-
- const Variable*
- var_value() const
- {
- go_assert(this->classification_ == NAMED_OBJECT_VAR);
- return this->u_.var_value;
- }
-
- Result_variable*
- result_var_value()
- {
- go_assert(this->classification_ == NAMED_OBJECT_RESULT_VAR);
- return this->u_.result_var_value;
- }
-
- const Result_variable*
- result_var_value() const
- {
- go_assert(this->classification_ == NAMED_OBJECT_RESULT_VAR);
- return this->u_.result_var_value;
- }
-
- Function*
- func_value()
- {
- go_assert(this->classification_ == NAMED_OBJECT_FUNC);
- return this->u_.func_value;
- }
-
- const Function*
- func_value() const
- {
- go_assert(this->classification_ == NAMED_OBJECT_FUNC);
- return this->u_.func_value;
- }
-
- Function_declaration*
- func_declaration_value()
- {
- go_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION);
- return this->u_.func_declaration_value;
- }
-
- const Function_declaration*
- func_declaration_value() const
- {
- go_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION);
- return this->u_.func_declaration_value;
- }
-
- Package*
- package_value()
- {
- go_assert(this->classification_ == NAMED_OBJECT_PACKAGE);
- return this->u_.package_value;
- }
-
- const Package*
- package_value() const
- {
- go_assert(this->classification_ == NAMED_OBJECT_PACKAGE);
- return this->u_.package_value;
- }
-
- const std::string&
- name() const
- { return this->name_; }
-
- // Return the name to use in an error message. The difference is
- // that if this Named_object is defined in a different package, this
- // will return PACKAGE.NAME.
- std::string
- message_name() const;
-
- const Package*
- package() const
- { return this->package_; }
-
- // Resolve an unknown value if possible. This returns the same
- // Named_object or a new one.
- Named_object*
- resolve()
- {
- Named_object* ret = this;
- if (this->is_unknown())
- {
- Named_object* r = this->unknown_value()->real_named_object();
- if (r != NULL)
- ret = r;
- }
- return ret;
- }
-
- const Named_object*
- resolve() const
- {
- const Named_object* ret = this;
- if (this->is_unknown())
- {
- const Named_object* r = this->unknown_value()->real_named_object();
- if (r != NULL)
- ret = r;
- }
- return ret;
- }
-
- // The location where this object was defined or referenced.
- Location
- location() const;
-
- // Convert a variable to the backend representation.
- Bvariable*
- get_backend_variable(Gogo*, Named_object* function);
-
- // Return a tree for the external identifier for this object.
- tree
- get_id(Gogo*);
-
- // Return a tree representing this object.
- tree
- get_tree(Gogo*, Named_object* function);
-
- // Define a type declaration.
- void
- set_type_value(Named_type*);
-
- // Define a function declaration.
- void
- set_function_value(Function*);
-
- // Declare an unknown name as a type declaration.
- void
- declare_as_type();
-
- // Export this object.
- void
- export_named_object(Export*) const;
-
- private:
- Named_object(const std::string&, const Package*, Classification);
-
- // The name of the object.
- std::string name_;
- // The package that this object is in. This is NULL if it is in the
- // file we are compiling.
- const Package* package_;
- // The type of object this is.
- Classification classification_;
- // The real data.
- union
- {
- Unknown_name* unknown_value;
- Named_constant* const_value;
- Named_type* type_value;
- Type_declaration* type_declaration;
- Variable* var_value;
- Result_variable* result_var_value;
- Function* func_value;
- Function_declaration* func_declaration_value;
- Package* package_value;
- } u_;
- // The DECL tree for this object if we have already converted it.
- tree tree_;
-};
-
-// A binding contour. This binds names to objects.
-
-class Bindings
-{
- public:
- // Type for mapping from names to objects.
- typedef Unordered_map(std::string, Named_object*) Contour;
-
- Bindings(Bindings* enclosing);
-
- // Add an erroneous name.
- Named_object*
- add_erroneous_name(const std::string& name)
- { return this->add_named_object(Named_object::make_erroneous_name(name)); }
-
- // Add an unknown name.
- Named_object*
- add_unknown_name(const std::string& name, Location location)
- {
- return this->add_named_object(Named_object::make_unknown_name(name,
- location));
- }
-
- // Add a constant.
- Named_object*
- add_constant(const Typed_identifier& tid, const Package* package,
- Expression* expr, int iota_value)
- {
- return this->add_named_object(Named_object::make_constant(tid, package,
- expr,
- iota_value));
- }
-
- // Add a type.
- Named_object*
- add_type(const std::string& name, const Package* package, Type* type,
- Location location)
- {
- return this->add_named_object(Named_object::make_type(name, package, type,
- location));
- }
-
- // Add a named type. This is used for builtin types, and to add an
- // imported type to the global scope.
- Named_object*
- add_named_type(Named_type* named_type);
-
- // Add a type declaration.
- Named_object*
- add_type_declaration(const std::string& name, const Package* package,
- Location location)
- {
- Named_object* no = Named_object::make_type_declaration(name, package,
- location);
- return this->add_named_object(no);
- }
-
- // Add a variable.
- Named_object*
- add_variable(const std::string& name, const Package* package,
- Variable* variable)
- {
- return this->add_named_object(Named_object::make_variable(name, package,
- variable));
- }
-
- // Add a result variable.
- Named_object*
- add_result_variable(const std::string& name, Result_variable* result)
- {
- return this->add_named_object(Named_object::make_result_variable(name,
- result));
- }
-
- // Add a function.
- Named_object*
- add_function(const std::string& name, const Package*, Function* function);
-
- // Add a function declaration.
- Named_object*
- add_function_declaration(const std::string& name, const Package* package,
- Function_type* type, Location location);
-
- // Add a package. The location is the location of the import
- // statement.
- Named_object*
- add_package(const std::string& alias, Package* package)
- {
- Named_object* no = Named_object::make_package(alias, package);
- return this->add_named_object(no);
- }
-
- // Define a type which was already declared.
- void
- define_type(Named_object*, Named_type*);
-
- // Add a method to the list of objects. This is not added to the
- // lookup table.
- void
- add_method(Named_object*);
-
- // Add a named object to this binding.
- Named_object*
- add_named_object(Named_object* no)
- { return this->add_named_object_to_contour(&this->bindings_, no); }
-
- // Clear all names in file scope from the bindings.
- void
- clear_file_scope(Gogo*);
-
- // Look up a name in this binding contour and in any enclosing
- // binding contours. This returns NULL if the name is not found.
- Named_object*
- lookup(const std::string&) const;
-
- // Look up a name in this binding contour without looking in any
- // enclosing binding contours. Returns NULL if the name is not found.
- Named_object*
- lookup_local(const std::string&) const;
-
- // Remove a name.
- void
- remove_binding(Named_object*);
-
- // Mark all variables as used. This is used for some types of parse
- // error.
- void
- mark_locals_used();
-
- // Traverse the tree. See the Traverse class.
- int
- traverse(Traverse*, bool is_global);
-
- // Iterate over definitions. This does not include things which
- // were only declared.
-
- typedef std::vector<Named_object*>::const_iterator
- const_definitions_iterator;
-
- const_definitions_iterator
- begin_definitions() const
- { return this->named_objects_.begin(); }
-
- const_definitions_iterator
- end_definitions() const
- { return this->named_objects_.end(); }
-
- // Return the number of definitions.
- size_t
- size_definitions() const
- { return this->named_objects_.size(); }
-
- // Return whether there are no definitions.
- bool
- empty_definitions() const
- { return this->named_objects_.empty(); }
-
- // Iterate over declarations. This is everything that has been
- // declared, which includes everything which has been defined.
-
- typedef Contour::const_iterator const_declarations_iterator;
-
- const_declarations_iterator
- begin_declarations() const
- { return this->bindings_.begin(); }
-
- const_declarations_iterator
- end_declarations() const
- { return this->bindings_.end(); }
-
- // Return the number of declarations.
- size_t
- size_declarations() const
- { return this->bindings_.size(); }
-
- // Return whether there are no declarations.
- bool
- empty_declarations() const
- { return this->bindings_.empty(); }
-
- // Return the first declaration.
- Named_object*
- first_declaration()
- { return this->bindings_.empty() ? NULL : this->bindings_.begin()->second; }
-
- private:
- Named_object*
- add_named_object_to_contour(Contour*, Named_object*);
-
- Named_object*
- new_definition(Named_object*, Named_object*);
-
- // Enclosing bindings.
- Bindings* enclosing_;
- // The list of objects.
- std::vector<Named_object*> named_objects_;
- // The mapping from names to objects.
- Contour bindings_;
-};
-
-// A label.
-
-class Label
-{
- public:
- Label(const std::string& name)
- : name_(name), location_(Linemap::unknown_location()), snapshot_(NULL),
- refs_(), is_used_(false), blabel_(NULL)
- { }
-
- // Return the label's name.
- const std::string&
- name() const
- { return this->name_; }
-
- // Return whether the label has been defined.
- bool
- is_defined() const
- { return !Linemap::is_unknown_location(this->location_); }
-
- // Return whether the label has been used.
- bool
- is_used() const
- { return this->is_used_; }
-
- // Record that the label is used.
- void
- set_is_used()
- { this->is_used_ = true; }
-
- // Return the location of the definition.
- Location
- location() const
- { return this->location_; }
-
- // Return the bindings snapshot.
- Bindings_snapshot*
- snapshot() const
- { return this->snapshot_; }
-
- // Add a snapshot of a goto which refers to this label.
- void
- add_snapshot_ref(Bindings_snapshot* snapshot)
- {
- go_assert(Linemap::is_unknown_location(this->location_));
- this->refs_.push_back(snapshot);
- }
-
- // Return the list of snapshots of goto statements which refer to
- // this label.
- const std::vector<Bindings_snapshot*>&
- refs() const
- { return this->refs_; }
-
- // Clear the references.
- void
- clear_refs();
-
- // Define the label at LOCATION with the given bindings snapshot.
- void
- define(Location location, Bindings_snapshot* snapshot)
- {
- go_assert(Linemap::is_unknown_location(this->location_)
- && this->snapshot_ == NULL);
- this->location_ = location;
- this->snapshot_ = snapshot;
- }
-
- // Return the backend representation for this label.
- Blabel*
- get_backend_label(Translate_context*);
-
- // Return an expression for the address of this label. This is used
- // to get the return address of a deferred function to see whether
- // the function may call recover.
- Bexpression*
- get_addr(Translate_context*, Location location);
-
- private:
- // The name of the label.
- std::string name_;
- // The location of the definition. This is 0 if the label has not
- // yet been defined.
- Location location_;
- // A snapshot of the set of bindings defined at this label, used to
- // issue errors about invalid goto statements.
- Bindings_snapshot* snapshot_;
- // A list of snapshots of goto statements which refer to this label.
- std::vector<Bindings_snapshot*> refs_;
- // Whether the label has been used.
- bool is_used_;
- // The backend representation.
- Blabel* blabel_;
-};
-
-// An unnamed label. These are used when lowering loops.
-
-class Unnamed_label
-{
- public:
- Unnamed_label(Location location)
- : location_(location), blabel_(NULL)
- { }
-
- // Get the location where the label is defined.
- Location
- location() const
- { return this->location_; }
-
- // Set the location where the label is defined.
- void
- set_location(Location location)
- { this->location_ = location; }
-
- // Return a statement which defines this label.
- Bstatement*
- get_definition(Translate_context*);
-
- // Return a goto to this label from LOCATION.
- Bstatement*
- get_goto(Translate_context*, Location location);
-
- private:
- // Return the backend representation.
- Blabel*
- get_blabel(Translate_context*);
-
- // The location where the label is defined.
- Location location_;
- // The backend representation of this label.
- Blabel* blabel_;
-};
-
-// An imported package.
-
-class Package
-{
- public:
- Package(const std::string& pkgpath, Location location);
-
- // Get the package path used for all symbols exported from this
- // package.
- const std::string&
- pkgpath() const
- { return this->pkgpath_; }
-
- // Return the package path to use for a symbol name.
- const std::string&
- pkgpath_symbol() const
- { return this->pkgpath_symbol_; }
-
- // Return the location of the import statement.
- Location
- location() const
- { return this->location_; }
-
- // Return whether we know the name of this package yet.
- bool
- has_package_name() const
- { return !this->package_name_.empty(); }
-
- // The name that this package uses in its package clause. This may
- // be different from the name in the associated Named_object if the
- // import statement used an alias.
- const std::string&
- package_name() const
- {
- go_assert(!this->package_name_.empty());
- return this->package_name_;
- }
-
- // The priority of this package. The init function of packages with
- // lower priority must be run before the init function of packages
- // with higher priority.
- int
- priority() const
- { return this->priority_; }
-
- // Set the priority.
- void
- set_priority(int priority);
-
- // Return the bindings.
- Bindings*
- bindings()
- { return this->bindings_; }
-
- // Whether some symbol from the package was used.
- bool
- used() const
- { return this->used_; }
-
- // Note that some symbol from this package was used.
- void
- set_used() const
- { this->used_ = true; }
-
- // Clear the used field for the next file.
- void
- clear_used()
- { this->used_ = false; }
-
- // Whether this package was imported in the current file.
- bool
- is_imported() const
- { return this->is_imported_; }
-
- // Note that this package was imported in the current file.
- void
- set_is_imported()
- { this->is_imported_ = true; }
-
- // Clear the imported field for the next file.
- void
- clear_is_imported()
- { this->is_imported_ = false; }
-
- // Whether this package was imported with a name of "_".
- bool
- uses_sink_alias() const
- { return this->uses_sink_alias_; }
-
- // Note that this package was imported with a name of "_".
- void
- set_uses_sink_alias()
- { this->uses_sink_alias_ = true; }
-
- // Clear the sink alias field for the next file.
- void
- clear_uses_sink_alias()
- { this->uses_sink_alias_ = false; }
-
- // Look up a name in the package. Returns NULL if the name is not
- // found.
- Named_object*
- lookup(const std::string& name) const
- { return this->bindings_->lookup(name); }
-
- // Set the name of the package.
- void
- set_package_name(const std::string& name, Location);
-
- // Set the location of the package. This is used to record the most
- // recent import location.
- void
- set_location(Location location)
- { this->location_ = location; }
-
- // Add a constant to the package.
- Named_object*
- add_constant(const Typed_identifier& tid, Expression* expr)
- { return this->bindings_->add_constant(tid, this, expr, 0); }
-
- // Add a type to the package.
- Named_object*
- add_type(const std::string& name, Type* type, Location location)
- { return this->bindings_->add_type(name, this, type, location); }
-
- // Add a type declaration to the package.
- Named_object*
- add_type_declaration(const std::string& name, Location location)
- { return this->bindings_->add_type_declaration(name, this, location); }
-
- // Add a variable to the package.
- Named_object*
- add_variable(const std::string& name, Variable* variable)
- { return this->bindings_->add_variable(name, this, variable); }
-
- // Add a function declaration to the package.
- Named_object*
- add_function_declaration(const std::string& name, Function_type* type,
- Location loc)
- { return this->bindings_->add_function_declaration(name, this, type, loc); }
-
- // Determine types of constants.
- void
- determine_types();
-
- private:
- // The package path for type reflection data.
- std::string pkgpath_;
- // The package path for symbol names.
- std::string pkgpath_symbol_;
- // The name that this package uses in the package clause. This may
- // be the empty string if it is not yet known.
- std::string package_name_;
- // The names in this package.
- Bindings* bindings_;
- // The priority of this package. A package has a priority higher
- // than the priority of all of the packages that it imports. This
- // is used to run init functions in the right order.
- int priority_;
- // The location of the import statement.
- Location location_;
- // True if some name from this package was used. This is mutable
- // because we can use a package even if we have a const pointer to
- // it.
- mutable bool used_;
- // True if this package was imported in the current file.
- bool is_imported_;
- // True if this package was imported with a name of "_".
- bool uses_sink_alias_;
-};
-
-// Return codes for the traversal functions. This is not an enum
-// because we want to be able to declare traversal functions in other
-// header files without including this one.
-
-// Continue traversal as usual.
-const int TRAVERSE_CONTINUE = -1;
-
-// Exit traversal.
-const int TRAVERSE_EXIT = 0;
-
-// Continue traversal, but skip components of the current object.
-// E.g., if this is returned by Traverse::statement, we do not
-// traverse the expressions in the statement even if
-// traverse_expressions is set in the traverse_mask.
-const int TRAVERSE_SKIP_COMPONENTS = 1;
-
-// This class is used when traversing the parse tree. The caller uses
-// a subclass which overrides functions as desired.
-
-class Traverse
-{
- public:
- // These bitmasks say what to traverse.
- static const unsigned int traverse_variables = 0x1;
- static const unsigned int traverse_constants = 0x2;
- static const unsigned int traverse_functions = 0x4;
- static const unsigned int traverse_blocks = 0x8;
- static const unsigned int traverse_statements = 0x10;
- static const unsigned int traverse_expressions = 0x20;
- static const unsigned int traverse_types = 0x40;
-
- Traverse(unsigned int traverse_mask)
- : traverse_mask_(traverse_mask), types_seen_(NULL), expressions_seen_(NULL)
- { }
-
- virtual ~Traverse();
-
- // The bitmask of what to traverse.
- unsigned int
- traverse_mask() const
- { return this->traverse_mask_; }
-
- // Record that we are going to traverse a type. This returns true
- // if the type has already been seen in this traversal. This is
- // required because types, unlike expressions, can form a circular
- // graph.
- bool
- remember_type(const Type*);
-
- // Record that we are going to see an expression. This returns true
- // if the expression has already been seen in this traversal. This
- // is only needed for cases where multiple expressions can point to
- // a single one.
- bool
- remember_expression(const Expression*);
-
- // These functions return one of the TRAVERSE codes defined above.
-
- // If traverse_variables is set in the mask, this is called for
- // every variable in the tree.
- virtual int
- variable(Named_object*);
-
- // If traverse_constants is set in the mask, this is called for
- // every named constant in the tree. The bool parameter is true for
- // a global constant.
- virtual int
- constant(Named_object*, bool);
-
- // If traverse_functions is set in the mask, this is called for
- // every function in the tree.
- virtual int
- function(Named_object*);
-
- // If traverse_blocks is set in the mask, this is called for every
- // block in the tree.
- virtual int
- block(Block*);
-
- // If traverse_statements is set in the mask, this is called for
- // every statement in the tree.
- virtual int
- statement(Block*, size_t* index, Statement*);
-
- // If traverse_expressions is set in the mask, this is called for
- // every expression in the tree.
- virtual int
- expression(Expression**);
-
- // If traverse_types is set in the mask, this is called for every
- // type in the tree.
- virtual int
- type(Type*);
-
- private:
- // A hash table for types we have seen during this traversal. Note
- // that this uses the default hash functions for pointers rather
- // than Type_hash_identical and Type_identical. This is because for
- // traversal we care about seeing a specific type structure. If
- // there are two separate instances of identical types, we want to
- // traverse both.
- typedef Unordered_set(const Type*) Types_seen;
-
- typedef Unordered_set(const Expression*) Expressions_seen;
-
- // Bitmask of what sort of objects to traverse.
- unsigned int traverse_mask_;
- // Types which have been seen in this traversal.
- Types_seen* types_seen_;
- // Expressions which have been seen in this traversal.
- Expressions_seen* expressions_seen_;
-};
-
-// A class which makes it easier to insert new statements before the
-// current statement during a traversal.
-
-class Statement_inserter
-{
- public:
- // Empty constructor.
- Statement_inserter()
- : block_(NULL), pindex_(NULL), gogo_(NULL), var_(NULL)
- { }
-
- // Constructor for a statement in a block.
- Statement_inserter(Block* block, size_t *pindex)
- : block_(block), pindex_(pindex), gogo_(NULL), var_(NULL)
- { }
-
- // Constructor for a global variable.
- Statement_inserter(Gogo* gogo, Variable* var)
- : block_(NULL), pindex_(NULL), gogo_(gogo), var_(var)
- { go_assert(var->is_global()); }
-
- // We use the default copy constructor and assignment operator.
-
- // Insert S before the statement we are traversing, or before the
- // initialization expression of a global variable.
- void
- insert(Statement* s);
-
- private:
- // The block that the statement is in.
- Block* block_;
- // The index of the statement that we are traversing.
- size_t* pindex_;
- // The IR, needed when looking at an initializer expression for a
- // global variable.
- Gogo* gogo_;
- // The global variable, when looking at an initializer expression.
- Variable* var_;
-};
-
-// When translating the gogo IR into the backend data structure, this
-// is the context we pass down the blocks and statements.
-
-class Translate_context
-{
- public:
- Translate_context(Gogo* gogo, Named_object* function, Block* block,
- Bblock* bblock)
- : gogo_(gogo), backend_(gogo->backend()), function_(function),
- block_(block), bblock_(bblock), is_const_(false)
- { }
-
- // Accessors.
-
- Gogo*
- gogo()
- { return this->gogo_; }
-
- Backend*
- backend()
- { return this->backend_; }
-
- Named_object*
- function()
- { return this->function_; }
-
- Block*
- block()
- { return this->block_; }
-
- Bblock*
- bblock()
- { return this->bblock_; }
-
- bool
- is_const()
- { return this->is_const_; }
-
- // Make a constant context.
- void
- set_is_const()
- { this->is_const_ = true; }
-
- private:
- // The IR for the entire compilation unit.
- Gogo* gogo_;
- // The generator for the backend data structures.
- Backend* backend_;
- // The function we are currently translating. NULL if not in a
- // function, e.g., the initializer of a global variable.
- Named_object* function_;
- // The block we are currently translating. NULL if not in a
- // function.
- Block *block_;
- // The backend representation of the current block. NULL if block_
- // is NULL.
- Bblock* bblock_;
- // Whether this is being evaluated in a constant context. This is
- // used for type descriptor initializers.
- bool is_const_;
-};
-
-// Runtime error codes. These must match the values in
-// libgo/runtime/go-runtime-error.c.
-
-// Slice index out of bounds: negative or larger than the length of
-// the slice.
-static const int RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS = 0;
-
-// Array index out of bounds.
-static const int RUNTIME_ERROR_ARRAY_INDEX_OUT_OF_BOUNDS = 1;
-
-// String index out of bounds.
-static const int RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS = 2;
-
-// Slice slice out of bounds: negative or larger than the length of
-// the slice or high bound less than low bound.
-static const int RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS = 3;
-
-// Array slice out of bounds.
-static const int RUNTIME_ERROR_ARRAY_SLICE_OUT_OF_BOUNDS = 4;
-
-// String slice out of bounds.
-static const int RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS = 5;
-
-// Dereference of nil pointer. This is used when there is a
-// dereference of a pointer to a very large struct or array, to ensure
-// that a gigantic array is not used a proxy to access random memory
-// locations.
-static const int RUNTIME_ERROR_NIL_DEREFERENCE = 6;
-
-// Slice length or capacity out of bounds in make: negative or
-// overflow or length greater than capacity.
-static const int RUNTIME_ERROR_MAKE_SLICE_OUT_OF_BOUNDS = 7;
-
-// Map capacity out of bounds in make: negative or overflow.
-static const int RUNTIME_ERROR_MAKE_MAP_OUT_OF_BOUNDS = 8;
-
-// Channel capacity out of bounds in make: negative or overflow.
-static const int RUNTIME_ERROR_MAKE_CHAN_OUT_OF_BOUNDS = 9;
-
-// Division by zero.
-static const int RUNTIME_ERROR_DIVISION_BY_ZERO = 10;
-
-// This is used by some of the langhooks.
-extern Gogo* go_get_gogo();
-
-// Whether we have seen any errors. FIXME: Replace with a backend
-// interface.
-extern bool saw_errors();
-
-#endif // !defined(GO_GOGO_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/import-archive.cc b/gcc-4.8.1/gcc/go/gofrontend/import-archive.cc
deleted file mode 100644
index 9a1d5b3d7..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/import-archive.cc
+++ /dev/null
@@ -1,660 +0,0 @@
-// import-archive.cc -- Go frontend read import data from an archive file.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "import.h"
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-// Archive magic numbers.
-
-static const char armag[] =
-{
- '!', '<', 'a', 'r', 'c', 'h', '>', '\n'
-};
-
-static const char armagt[] =
-{
- '!', '<', 't', 'h', 'i', 'n', '>', '\n'
-};
-
-static const char arfmag[2] = { '`', '\n' };
-
-// The header of an entry in an archive. This is all readable text,
-// padded with spaces where necesary.
-
-struct Archive_header
-{
- // The entry name.
- char ar_name[16];
- // The file modification time.
- char ar_date[12];
- // The user's UID in decimal.
- char ar_uid[6];
- // The user's GID in decimal.
- char ar_gid[6];
- // The file mode in octal.
- char ar_mode[8];
- // The file size in decimal.
- char ar_size[10];
- // The final magic code.
- char ar_fmag[2];
-};
-
-// The functions in this file extract Go export data from an archive.
-
-const int Import::archive_magic_len;
-
-// Return true if BYTES, which are from the start of the file, are an
-// archive magic number.
-
-bool
-Import::is_archive_magic(const char* bytes)
-{
- return (memcmp(bytes, armag, Import::archive_magic_len) == 0
- || memcmp(bytes, armagt, Import::archive_magic_len) == 0);
-}
-
-// An object used to read an archive file.
-
-class Archive_file
-{
- public:
- Archive_file(const std::string& filename, int fd, Location location)
- : filename_(filename), fd_(fd), filesize_(-1), extended_names_(),
- is_thin_archive_(false), location_(location), nested_archives_()
- { }
-
- // Initialize.
- bool
- initialize();
-
- // Return the file name.
- const std::string&
- filename() const
- { return this->filename_; }
-
- // Get the file size.
- off_t
- filesize() const
- { return this->filesize_; }
-
- // Return whether this is a thin archive.
- bool
- is_thin_archive() const
- { return this->is_thin_archive_; }
-
- // Return the location of the import statement.
- Location
- location() const
- { return this->location_; }
-
- // Read bytes.
- bool
- read(off_t offset, off_t size, char*);
-
- // Read the archive header at OFF, setting *PNAME, *SIZE, and
- // *NESTED_OFF.
- bool
- read_header(off_t off, std::string* pname, off_t* size, off_t* nested_off);
-
- // Interpret the header of HDR, the header of the archive member at
- // file offset OFF. Return whether it succeeded. Set *SIZE to the
- // size of the member. Set *PNAME to the name of the member. Set
- // *NESTED_OFF to the offset in a nested archive.
- bool
- interpret_header(const Archive_header* hdr, off_t off,
- std::string* pname, off_t* size, off_t* nested_off) const;
-
- // Get the file and offset for an archive member.
- bool
- get_file_and_offset(off_t off, const std::string& hdrname,
- off_t nested_off, int* memfd, off_t* memoff,
- std::string* memname);
-
- private:
- // For keeping track of open nested archives in a thin archive file.
- typedef std::map<std::string, Archive_file*> Nested_archive_table;
-
- // The name of the file.
- std::string filename_;
- // The file descriptor.
- int fd_;
- // The file size;
- off_t filesize_;
- // The extended name table.
- std::string extended_names_;
- // Whether this is a thin archive.
- bool is_thin_archive_;
- // The location of the import statements.
- Location location_;
- // Table of nested archives.
- Nested_archive_table nested_archives_;
-};
-
-bool
-Archive_file::initialize()
-{
- struct stat st;
- if (fstat(this->fd_, &st) < 0)
- {
- error_at(this->location_, "%s: %m", this->filename_.c_str());
- return false;
- }
- this->filesize_ = st.st_size;
-
- char buf[sizeof(armagt)];
- if (::lseek(this->fd_, 0, SEEK_SET) < 0
- || ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt))
- {
- error_at(this->location_, "%s: %m", this->filename_.c_str());
- return false;
- }
- this->is_thin_archive_ = memcmp(buf, armagt, sizeof(armagt)) == 0;
-
- if (this->filesize_ == sizeof(armag))
- {
- // Empty archive.
- return true;
- }
-
- // Look for the extended name table.
- std::string filename;
- off_t size;
- if (!this->read_header(sizeof(armagt), &filename, &size, NULL))
- return false;
- if (filename.empty())
- {
- // We found the symbol table.
- off_t off = sizeof(armagt) + sizeof(Archive_header) + size;
- if ((off & 1) != 0)
- ++off;
- if (!this->read_header(off, &filename, &size, NULL))
- filename.clear();
- }
- if (filename == "/")
- {
- char* rdbuf = new char[size];
- if (::read(this->fd_, rdbuf, size) != size)
- {
- error_at(this->location_, "%s: could not read extended names",
- filename.c_str());
- delete[] rdbuf;
- return false;
- }
- this->extended_names_.assign(rdbuf, size);
- delete[] rdbuf;
- }
-
- return true;
-}
-
-// Read bytes from the file.
-
-bool
-Archive_file::read(off_t offset, off_t size, char* buf)
-{
- if (::lseek(this->fd_, offset, SEEK_SET) < 0
- || ::read(this->fd_, buf, size) != size)
- {
- error_at(this->location_, "%s: %m", this->filename_.c_str());
- return false;
- }
- return true;
-}
-
-// Read the header at OFF. Set *PNAME to the name, *SIZE to the size,
-// and *NESTED_OFF to the nested offset.
-
-bool
-Archive_file::read_header(off_t off, std::string* pname, off_t* size,
- off_t* nested_off)
-{
- Archive_header hdr;
- if (::lseek(this->fd_, off, SEEK_SET) < 0)
- {
- error_at(this->location_, "%s: %m", this->filename_.c_str());
- return false;
- }
- ssize_t got = ::read(this->fd_, &hdr, sizeof hdr);
- if (got != sizeof hdr)
- {
- if (got < 0)
- error_at(this->location_, "%s: %m", this->filename_.c_str());
- else if (got > 0)
- error_at(this->location_, "%s: short archive header at %ld",
- this->filename_.c_str(), static_cast<long>(off));
- else
- error_at(this->location_, "%s: unexpected EOF at %ld",
- this->filename_.c_str(), static_cast<long>(off));
- }
- off_t local_nested_off;
- if (!this->interpret_header(&hdr, off, pname, size, &local_nested_off))
- return false;
- if (nested_off != NULL)
- *nested_off = local_nested_off;
- return true;
-}
-
-// Interpret the header of HDR, the header of the archive member at
-// file offset OFF.
-
-bool
-Archive_file::interpret_header(const Archive_header* hdr, off_t off,
- std::string* pname, off_t* size,
- off_t* nested_off) const
-{
- if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
- {
- error_at(this->location_, "%s: malformed archive header at %lu",
- this->filename_.c_str(), static_cast<unsigned long>(off));
- return false;
- }
-
- const int size_string_size = sizeof hdr->ar_size;
- char size_string[size_string_size + 1];
- memcpy(size_string, hdr->ar_size, size_string_size);
- char* ps = size_string + size_string_size;
- while (ps[-1] == ' ')
- --ps;
- *ps = '\0';
-
- errno = 0;
- char* end;
- *size = strtol(size_string, &end, 10);
- if (*end != '\0'
- || *size < 0
- || (*size == LONG_MAX && errno == ERANGE))
- {
- error_at(this->location_, "%s: malformed archive header size at %lu",
- this->filename_.c_str(), static_cast<unsigned long>(off));
- return false;
- }
-
- *nested_off = 0;
- if (hdr->ar_name[0] != '/')
- {
- const char* name_end = strchr(hdr->ar_name, '/');
- if (name_end == NULL
- || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
- {
- error_at(this->location_, "%s: malformed archive header name at %lu",
- this->filename_.c_str(), static_cast<unsigned long>(off));
- return false;
- }
- pname->assign(hdr->ar_name, name_end - hdr->ar_name);
- }
- else if (hdr->ar_name[1] == ' ')
- {
- // This is the symbol table.
- pname->clear();
- }
- else if (hdr->ar_name[1] == '/')
- {
- // This is the extended name table.
- pname->assign(1, '/');
- }
- else
- {
- errno = 0;
- long x = strtol(hdr->ar_name + 1, &end, 10);
- long y = 0;
- if (*end == ':')
- y = strtol(end + 1, &end, 10);
- if (*end != ' '
- || x < 0
- || (x == LONG_MAX && errno == ERANGE)
- || static_cast<size_t>(x) >= this->extended_names_.size())
- {
- error_at(this->location_, "%s: bad extended name index at %lu",
- this->filename_.c_str(), static_cast<unsigned long>(off));
- return false;
- }
-
- const char* name = this->extended_names_.data() + x;
- const char* name_end = strchr(name, '\n');
- if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
- || name_end[-1] != '/')
- {
- error_at(this->location_, "%s: bad extended name entry at header %lu",
- this->filename_.c_str(), static_cast<unsigned long>(off));
- return false;
- }
- pname->assign(name, name_end - 1 - name);
- *nested_off = y;
- }
-
- return true;
-}
-
-// Get the file and offset for an archive member.
-
-bool
-Archive_file::get_file_and_offset(off_t off, const std::string& hdrname,
- off_t nested_off, int* memfd, off_t* memoff,
- std::string* memname)
-{
- if (!this->is_thin_archive_)
- {
- *memfd = this->fd_;
- *memoff = off + sizeof(Archive_header);
- *memname = this->filename_ + '(' + hdrname + ')';
- return true;
- }
-
- std::string filename = hdrname;
- if (!IS_ABSOLUTE_PATH(filename.c_str()))
- {
- const char* archive_path = this->filename_.c_str();
- const char* basename = lbasename(archive_path);
- if (basename > archive_path)
- filename.replace(0, 0,
- this->filename_.substr(0, basename - archive_path));
- }
-
- if (nested_off > 0)
- {
- // This is a member of a nested archive.
- Archive_file* nfile;
- Nested_archive_table::const_iterator p =
- this->nested_archives_.find(filename);
- if (p != this->nested_archives_.end())
- nfile = p->second;
- else
- {
- int nfd = open(filename.c_str(), O_RDONLY | O_BINARY);
- if (nfd < 0)
- {
- error_at(this->location_, "%s: can't open nested archive %s",
- this->filename_.c_str(), filename.c_str());
- return false;
- }
- nfile = new Archive_file(filename, nfd, this->location_);
- if (!nfile->initialize())
- {
- delete nfile;
- return false;
- }
- this->nested_archives_[filename] = nfile;
- }
-
- std::string nname;
- off_t nsize;
- off_t nnested_off;
- if (!nfile->read_header(nested_off, &nname, &nsize, &nnested_off))
- return false;
- return nfile->get_file_and_offset(nested_off, nname, nnested_off,
- memfd, memoff, memname);
- }
-
- // An external member of a thin archive.
- *memfd = open(filename.c_str(), O_RDONLY | O_BINARY);
- if (*memfd < 0)
- {
- error_at(this->location_, "%s: %m", filename.c_str());
- return false;
- }
- *memoff = 0;
- *memname = filename;
- return true;
-}
-
-// An archive member iterator. This is more-or-less copied from gold.
-
-class Archive_iterator
-{
- public:
- // The header of an archive member. This is what this iterator
- // points to.
- struct Header
- {
- // The name of the member.
- std::string name;
- // The file offset of the member.
- off_t off;
- // The file offset of a nested archive member.
- off_t nested_off;
- // The size of the member.
- off_t size;
- };
-
- Archive_iterator(Archive_file* afile, off_t off)
- : afile_(afile), off_(off)
- { this->read_next_header(); }
-
- const Header&
- operator*() const
- { return this->header_; }
-
- const Header*
- operator->() const
- { return &this->header_; }
-
- Archive_iterator&
- operator++()
- {
- if (this->off_ == this->afile_->filesize())
- return *this;
- this->off_ += sizeof(Archive_header);
- if (!this->afile_->is_thin_archive())
- this->off_ += this->header_.size;
- if ((this->off_ & 1) != 0)
- ++this->off_;
- this->read_next_header();
- return *this;
- }
-
- Archive_iterator
- operator++(int)
- {
- Archive_iterator ret = *this;
- ++*this;
- return ret;
- }
-
- bool
- operator==(const Archive_iterator p) const
- { return this->off_ == p->off; }
-
- bool
- operator!=(const Archive_iterator p) const
- { return this->off_ != p->off; }
-
- private:
- void
- read_next_header();
-
- // The underlying archive file.
- Archive_file* afile_;
- // The current offset in the file.
- off_t off_;
- // The current archive header.
- Header header_;
-};
-
-// Read the next archive header.
-
-void
-Archive_iterator::read_next_header()
-{
- off_t filesize = this->afile_->filesize();
- while (true)
- {
- if (filesize - this->off_ < static_cast<off_t>(sizeof(Archive_header)))
- {
- if (filesize != this->off_)
- {
- error_at(this->afile_->location(),
- "%s: short archive header at %lu",
- this->afile_->filename().c_str(),
- static_cast<unsigned long>(this->off_));
- this->off_ = filesize;
- }
- this->header_.off = filesize;
- return;
- }
-
- char buf[sizeof(Archive_header)];
- if (!this->afile_->read(this->off_, sizeof(Archive_header), buf))
- {
- this->header_.off = filesize;
- return;
- }
-
- const Archive_header* hdr = reinterpret_cast<const Archive_header*>(buf);
- if (!this->afile_->interpret_header(hdr, this->off_, &this->header_.name,
- &this->header_.size,
- &this->header_.nested_off))
- {
- this->header_.off = filesize;
- return;
- }
- this->header_.off = this->off_;
-
- // Skip special members.
- if (!this->header_.name.empty() && this->header_.name != "/")
- return;
-
- this->off_ += sizeof(Archive_header) + this->header_.size;
- if ((this->off_ & 1) != 0)
- ++this->off_;
- }
-}
-
-// Initial iterator.
-
-Archive_iterator
-archive_begin(Archive_file* afile)
-{
- return Archive_iterator(afile, sizeof(armag));
-}
-
-// Final iterator.
-
-Archive_iterator
-archive_end(Archive_file* afile)
-{
- return Archive_iterator(afile, afile->filesize());
-}
-
-// A type of Import_stream which concatenates other Import_streams
-// together.
-
-class Stream_concatenate : public Import::Stream
-{
- public:
- Stream_concatenate()
- : inputs_()
- { }
-
- // Add a new stream.
- void
- add(Import::Stream* is)
- { this->inputs_.push_back(is); }
-
- protected:
- bool
- do_peek(size_t, const char**);
-
- void
- do_advance(size_t);
-
- private:
- std::list<Import::Stream*> inputs_;
-};
-
-// Peek ahead.
-
-bool
-Stream_concatenate::do_peek(size_t length, const char** bytes)
-{
- while (true)
- {
- if (this->inputs_.empty())
- return false;
- if (this->inputs_.front()->peek(length, bytes))
- return true;
- delete this->inputs_.front();
- this->inputs_.pop_front();
- }
-}
-
-// Advance.
-
-void
-Stream_concatenate::do_advance(size_t skip)
-{
- while (true)
- {
- if (this->inputs_.empty())
- return;
- if (!this->inputs_.front()->at_eof())
- {
- // We just assume that this will do the right thing. It
- // should be OK since we should never want to skip past
- // multiple streams.
- this->inputs_.front()->advance(skip);
- return;
- }
- delete this->inputs_.front();
- this->inputs_.pop_front();
- }
-}
-
-// Import data from an archive. We walk through the archive and
-// import data from each member.
-
-Import::Stream*
-Import::find_archive_export_data(const std::string& filename, int fd,
- Location location)
-{
- Archive_file afile(filename, fd, location);
- if (!afile.initialize())
- return NULL;
-
- Stream_concatenate* ret = new Stream_concatenate;
-
- bool any_data = false;
- bool any_members = false;
- Archive_iterator pend = archive_end(&afile);
- for (Archive_iterator p = archive_begin(&afile); p != pend; p++)
- {
- any_members = true;
- int member_fd;
- off_t member_off;
- std::string member_name;
- if (!afile.get_file_and_offset(p->off, p->name, p->nested_off,
- &member_fd, &member_off, &member_name))
- return NULL;
-
- Import::Stream* is = Import::find_object_export_data(member_name,
- member_fd,
- member_off,
- location);
- if (is != NULL)
- {
- ret->add(is);
- any_data = true;
- }
- }
-
- if (!any_members)
- {
- // It's normal to have an empty archive file when using gobuild.
- return new Stream_from_string("");
- }
-
- if (!any_data)
- {
- delete ret;
- return NULL;
- }
-
- return ret;
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/import.cc b/gcc-4.8.1/gcc/go/gofrontend/import.cc
deleted file mode 100644
index 4913100b5..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/import.cc
+++ /dev/null
@@ -1,960 +0,0 @@
-// import.cc -- Go frontend import declarations.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "filenames.h"
-#include "simple-object.h"
-
-#include "go-c.h"
-#include "gogo.h"
-#include "lex.h"
-#include "types.h"
-#include "export.h"
-#include "import.h"
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-// The list of paths we search for import files.
-
-static std::vector<std::string> search_path;
-
-// Add a directory to the search path. This is called from the option
-// handling language hook.
-
-GO_EXTERN_C
-void
-go_add_search_path(const char* path)
-{
- search_path.push_back(std::string(path));
-}
-
-// Find import data. This searches the file system for FILENAME and
-// returns a pointer to a Stream object to read the data that it
-// exports. If the file is not found, it returns NULL.
-
-// When FILENAME is not an absolute path and does not start with ./ or
-// ../, we use the search path provided by -I and -L options.
-
-// When FILENAME does start with ./ or ../, we use
-// RELATIVE_IMPORT_PATH as a prefix.
-
-// When FILENAME does not exist, we try modifying FILENAME to find the
-// file. We use the first of these which exists:
-// * We append ".gox".
-// * We turn the base of FILENAME into libFILENAME.so.
-// * We turn the base of FILENAME into libFILENAME.a.
-// * We append ".o".
-
-// When using a search path, we apply each of these transformations at
-// each entry on the search path before moving on to the next entry.
-// If the file exists, but does not contain any Go export data, we
-// stop; we do not keep looking for another file with the same name
-// later in the search path.
-
-Import::Stream*
-Import::open_package(const std::string& filename, Location location,
- const std::string& relative_import_path)
-{
- bool is_local;
- if (IS_ABSOLUTE_PATH(filename))
- is_local = true;
- else if (filename[0] == '.'
- && (filename[1] == '\0' || IS_DIR_SEPARATOR(filename[1])))
- is_local = true;
- else if (filename[0] == '.'
- && filename[1] == '.'
- && (filename[2] == '\0' || IS_DIR_SEPARATOR(filename[2])))
- is_local = true;
- else
- is_local = false;
-
- std::string fn = filename;
- if (is_local && !IS_ABSOLUTE_PATH(filename) && !relative_import_path.empty())
- {
- if (fn == ".")
- {
- // A special case.
- fn = relative_import_path;
- }
- else
- fn = relative_import_path + '/' + fn;
- is_local = false;
- }
-
- if (!is_local)
- {
- for (std::vector<std::string>::const_iterator p = search_path.begin();
- p != search_path.end();
- ++p)
- {
- std::string indir = *p;
- if (!indir.empty() && indir[indir.size() - 1] != '/')
- indir += '/';
- indir += fn;
- Stream* s = Import::try_package_in_directory(indir, location);
- if (s != NULL)
- return s;
- }
- }
-
- Stream* s = Import::try_package_in_directory(fn, location);
- if (s != NULL)
- return s;
-
- return NULL;
-}
-
-// Try to find the export data for FILENAME.
-
-Import::Stream*
-Import::try_package_in_directory(const std::string& filename,
- Location location)
-{
- std::string found_filename = filename;
- int fd = open(found_filename.c_str(), O_RDONLY | O_BINARY);
-
- if (fd >= 0)
- {
- struct stat s;
- if (fstat(fd, &s) >= 0 && S_ISDIR(s.st_mode))
- {
- close(fd);
- fd = -1;
- errno = EISDIR;
- }
- }
-
- if (fd < 0)
- {
- if (errno != ENOENT && errno != EISDIR)
- warning_at(location, 0, "%s: %m", filename.c_str());
-
- fd = Import::try_suffixes(&found_filename);
- if (fd < 0)
- return NULL;
- }
-
- // The export data may not be in this file.
- Stream* s = Import::find_export_data(found_filename, fd, location);
- if (s != NULL)
- return s;
-
- close(fd);
-
- error_at(location, "%s exists but does not contain any Go export data",
- found_filename.c_str());
-
- return NULL;
-}
-
-// Given import "*PFILENAME", where *PFILENAME does not exist, try
-// various suffixes. If we find one, set *PFILENAME to the one we
-// found. Return the open file descriptor.
-
-int
-Import::try_suffixes(std::string* pfilename)
-{
- std::string filename = *pfilename + ".gox";
- int fd = open(filename.c_str(), O_RDONLY | O_BINARY);
- if (fd >= 0)
- {
- *pfilename = filename;
- return fd;
- }
-
- const char* basename = lbasename(pfilename->c_str());
- size_t basename_pos = basename - pfilename->c_str();
- filename = pfilename->substr(0, basename_pos) + "lib" + basename + ".so";
- fd = open(filename.c_str(), O_RDONLY | O_BINARY);
- if (fd >= 0)
- {
- *pfilename = filename;
- return fd;
- }
-
- filename = pfilename->substr(0, basename_pos) + "lib" + basename + ".a";
- fd = open(filename.c_str(), O_RDONLY | O_BINARY);
- if (fd >= 0)
- {
- *pfilename = filename;
- return fd;
- }
-
- filename = *pfilename + ".o";
- fd = open(filename.c_str(), O_RDONLY | O_BINARY);
- if (fd >= 0)
- {
- *pfilename = filename;
- return fd;
- }
-
- return -1;
-}
-
-// Look for export data in the file descriptor FD.
-
-Import::Stream*
-Import::find_export_data(const std::string& filename, int fd,
- Location location)
-{
- // See if we can read this as an object file.
- Import::Stream* stream = Import::find_object_export_data(filename, fd, 0,
- location);
- if (stream != NULL)
- return stream;
-
- const int len = MAX(Export::v1_magic_len, Import::archive_magic_len);
-
- if (lseek(fd, 0, SEEK_SET) < 0)
- {
- error_at(location, "lseek %s failed: %m", filename.c_str());
- return NULL;
- }
-
- char buf[len];
- ssize_t c = read(fd, buf, len);
- if (c < len)
- return NULL;
-
- // Check for a file containing nothing but Go export data.
- if (memcmp(buf, Export::v1_magic, Export::v1_magic_len) == 0)
- return new Stream_from_file(fd);
-
- // See if we can read this as an archive.
- if (Import::is_archive_magic(buf))
- return Import::find_archive_export_data(filename, fd, location);
-
- return NULL;
-}
-
-// Look for export data in a simple_object.
-
-Import::Stream*
-Import::find_object_export_data(const std::string& filename,
- int fd,
- off_t offset,
- Location location)
-{
- char *buf;
- size_t len;
- int err;
- const char *errmsg = go_read_export_data(fd, offset, &buf, &len, &err);
- if (errmsg != NULL)
- {
- if (err == 0)
- error_at(location, "%s: %s", filename.c_str(), errmsg);
- else
- error_at(location, "%s: %s: %s", filename.c_str(), errmsg,
- xstrerror(err));
- return NULL;
- }
-
- if (buf == NULL)
- return NULL;
-
- return new Stream_from_buffer(buf, len);
-}
-
-// Class Import.
-
-// Construct an Import object. We make the builtin_types_ vector
-// large enough to hold all the builtin types.
-
-Import::Import(Stream* stream, Location location)
- : gogo_(NULL), stream_(stream), location_(location), package_(NULL),
- add_to_globals_(false),
- builtin_types_((- SMALLEST_BUILTIN_CODE) + 1),
- types_()
-{
-}
-
-// Import the data in the associated stream.
-
-Package*
-Import::import(Gogo* gogo, const std::string& local_name,
- bool is_local_name_exported)
-{
- // Hold on to the Gogo structure. Otherwise we need to pass it
- // through all the import functions, because we need it when reading
- // a type.
- this->gogo_ = gogo;
-
- // A stream of export data can include data from more than one input
- // file. Here we loop over each input file.
- Stream* stream = this->stream_;
- while (!stream->at_eof() && !stream->saw_error())
- {
- // The vector of types is package specific.
- this->types_.clear();
-
- stream->require_bytes(this->location_, Export::v1_magic,
- Export::v1_magic_len);
-
- this->require_c_string("package ");
- std::string package_name = this->read_identifier();
- this->require_c_string(";\n");
-
- std::string pkgpath;
- if (this->match_c_string("prefix "))
- {
- this->advance(7);
- std::string unique_prefix = this->read_identifier();
- this->require_c_string(";\n");
- pkgpath = unique_prefix + '.' + package_name;
- }
- else
- {
- this->require_c_string("pkgpath ");
- pkgpath = this->read_identifier();
- this->require_c_string(";\n");
- }
-
- this->package_ = gogo->add_imported_package(package_name, local_name,
- is_local_name_exported,
- pkgpath,
- this->location_,
- &this->add_to_globals_);
- if (this->package_ == NULL)
- {
- stream->set_saw_error();
- return NULL;
- }
-
- this->require_c_string("priority ");
- std::string priority_string = this->read_identifier();
- int prio;
- if (!this->string_to_int(priority_string, false, &prio))
- return NULL;
- this->package_->set_priority(prio);
- this->require_c_string(";\n");
-
- while (stream->match_c_string("import"))
- this->read_one_import();
-
- if (stream->match_c_string("init"))
- this->read_import_init_fns(gogo);
-
- // Loop over all the input data for this package.
- while (!stream->saw_error())
- {
- if (stream->match_c_string("const "))
- this->import_const();
- else if (stream->match_c_string("type "))
- this->import_type();
- else if (stream->match_c_string("var "))
- this->import_var();
- else if (stream->match_c_string("func "))
- this->import_func(this->package_);
- else if (stream->match_c_string("checksum "))
- break;
- else
- {
- error_at(this->location_,
- ("error in import data at %d: "
- "expected %<const%>, %<type%>, %<var%>, "
- "%<func%>, or %<checksum%>"),
- stream->pos());
- stream->set_saw_error();
- return NULL;
- }
- }
-
- // We currently ignore the checksum. In the future we could
- // store the checksum somewhere in the generated object and then
- // verify that the checksum matches at link time or at dynamic
- // load time.
- this->require_c_string("checksum ");
- stream->advance(Export::v1_checksum_len * 2);
- this->require_c_string(";\n");
- }
-
- return this->package_;
-}
-
-// Read an import line. We don't actually care about these.
-
-void
-Import::read_one_import()
-{
- this->require_c_string("import ");
- std::string package_name = this->read_identifier();
- this->require_c_string(" ");
- std::string pkgpath = this->read_identifier();
- this->require_c_string(" \"");
- Stream* stream = this->stream_;
- while (stream->peek_char() != '"')
- stream->advance(1);
- this->require_c_string("\";\n");
-
- Package* p = this->gogo_->register_package(pkgpath,
- Linemap::unknown_location());
- p->set_package_name(package_name, this->location());
-}
-
-// Read the list of import control functions.
-
-void
-Import::read_import_init_fns(Gogo* gogo)
-{
- this->require_c_string("init");
- while (!this->match_c_string(";"))
- {
- this->require_c_string(" ");
- std::string package_name = this->read_identifier();
- this->require_c_string(" ");
- std::string init_name = this->read_identifier();
- this->require_c_string(" ");
- std::string prio_string = this->read_identifier();
- int prio;
- if (!this->string_to_int(prio_string, false, &prio))
- return;
- gogo->add_import_init_fn(package_name, init_name, prio);
- }
- this->require_c_string(";\n");
-}
-
-// Import a constant.
-
-void
-Import::import_const()
-{
- std::string name;
- Type* type;
- Expression* expr;
- Named_constant::import_const(this, &name, &type, &expr);
- Typed_identifier tid(name, type, this->location_);
- Named_object* no = this->package_->add_constant(tid, expr);
- if (this->add_to_globals_)
- this->gogo_->add_named_object(no);
-}
-
-// Import a type.
-
-void
-Import::import_type()
-{
- Named_type* type;
- Named_type::import_named_type(this, &type);
-
- // The named type has been added to the package by the type import
- // process. Here we need to make it visible to the parser, and it
- // to the global bindings if necessary.
- type->set_is_visible();
-
- if (this->add_to_globals_)
- this->gogo_->add_named_type(type);
-}
-
-// Import a variable.
-
-void
-Import::import_var()
-{
- std::string name;
- Type* type;
- Variable::import_var(this, &name, &type);
- Variable* var = new Variable(type, NULL, true, false, false,
- this->location_);
- Named_object* no;
- no = this->package_->add_variable(name, var);
- if (this->add_to_globals_)
- this->gogo_->add_named_object(no);
-}
-
-// Import a function into PACKAGE. PACKAGE is normally
-// THIS->PACKAGE_, but it will be different for a method associated
-// with a type defined in a different package.
-
-Named_object*
-Import::import_func(Package* package)
-{
- std::string name;
- Typed_identifier* receiver;
- Typed_identifier_list* parameters;
- Typed_identifier_list* results;
- bool is_varargs;
- Function::import_func(this, &name, &receiver, &parameters, &results,
- &is_varargs);
- Function_type *fntype = Type::make_function_type(receiver, parameters,
- results, this->location_);
- if (is_varargs)
- fntype->set_is_varargs();
-
- Location loc = this->location_;
- Named_object* no;
- if (fntype->is_method())
- {
- Type* rtype = receiver->type();
-
- // We may still be reading the definition of RTYPE, so we have
- // to be careful to avoid calling base or convert. If RTYPE is
- // a named type or a forward declaration, then we know that it
- // is not a pointer, because we are reading a method on RTYPE
- // and named pointers can't have methods.
-
- if (rtype->classification() == Type::TYPE_POINTER)
- rtype = rtype->points_to();
-
- if (rtype->is_error_type())
- return NULL;
- else if (rtype->named_type() != NULL)
- no = rtype->named_type()->add_method_declaration(name, package, fntype,
- loc);
- else if (rtype->forward_declaration_type() != NULL)
- no = rtype->forward_declaration_type()->add_method_declaration(name,
- package,
- fntype,
- loc);
- else
- go_unreachable();
- }
- else
- {
- no = package->add_function_declaration(name, fntype, loc);
- if (this->add_to_globals_)
- this->gogo_->add_named_object(no);
- }
- return no;
-}
-
-// Read a type in the import stream. This records the type by the
-// type index. If the type is named, it registers the name, but marks
-// it as invisible.
-
-Type*
-Import::read_type()
-{
- Stream* stream = this->stream_;
- this->require_c_string("<type ");
-
- std::string number;
- int c;
- while (true)
- {
- c = stream->get_char();
- if (c != '-' && (c < '0' || c > '9'))
- break;
- number += c;
- }
-
- int index;
- if (!this->string_to_int(number, true, &index))
- return Type::make_error_type();
-
- if (c == '>')
- {
- // This type was already defined.
- if (index < 0
- ? (static_cast<size_t>(- index) >= this->builtin_types_.size()
- || this->builtin_types_[- index] == NULL)
- : (static_cast<size_t>(index) >= this->types_.size()
- || this->types_[index] == NULL))
- {
- error_at(this->location_,
- "error in import data at %d: bad type index %d",
- stream->pos(), index);
- stream->set_saw_error();
- return Type::make_error_type();
- }
-
- return index < 0 ? this->builtin_types_[- index] : this->types_[index];
- }
-
- if (c != ' ')
- {
- if (!stream->saw_error())
- error_at(this->location_,
- "error in import data at %d: expect %< %> or %<>%>'",
- stream->pos());
- stream->set_saw_error();
- stream->advance(1);
- return Type::make_error_type();
- }
-
- if (index <= 0
- || (static_cast<size_t>(index) < this->types_.size()
- && this->types_[index] != NULL))
- {
- error_at(this->location_,
- "error in import data at %d: type index already defined",
- stream->pos());
- stream->set_saw_error();
- return Type::make_error_type();
- }
-
- if (static_cast<size_t>(index) >= this->types_.size())
- {
- int newsize = std::max(static_cast<size_t>(index) + 1,
- this->types_.size() * 2);
- this->types_.resize(newsize, NULL);
- }
-
- if (stream->peek_char() != '"')
- {
- Type* type = Type::import_type(this);
- this->require_c_string(">");
- this->types_[index] = type;
- return type;
- }
-
- // This type has a name.
-
- stream->advance(1);
- std::string type_name;
- while ((c = stream->get_char()) != '"')
- type_name += c;
-
- // If this type is in the package we are currently importing, the
- // name will be .PKGPATH.NAME or simply NAME with no dots.
- // Otherwise, a non-hidden symbol will be PKGPATH.NAME and a hidden
- // symbol will be .PKGPATH.NAME.
- std::string pkgpath;
- if (type_name.find('.') != std::string::npos)
- {
- size_t start = 0;
- if (type_name[0] == '.')
- start = 1;
- size_t dot = type_name.rfind('.');
- pkgpath = type_name.substr(start, dot - start);
- if (type_name[0] != '.')
- type_name.erase(0, dot + 1);
- }
-
- this->require_c_string(" ");
-
- // The package name may follow. This is the name of the package in
- // the package clause of that package. The type name will include
- // the pkgpath, which may be different.
- std::string package_name;
- if (stream->peek_char() == '"')
- {
- stream->advance(1);
- while ((c = stream->get_char()) != '"')
- package_name += c;
- this->require_c_string(" ");
- }
-
- // Declare the type in the appropriate package. If we haven't seen
- // it before, mark it as invisible. We declare it before we read
- // the actual definition of the type, since the definition may refer
- // to the type itself.
- Package* package;
- if (pkgpath.empty() || pkgpath == this->gogo_->pkgpath())
- package = this->package_;
- else
- {
- package = this->gogo_->register_package(pkgpath,
- Linemap::unknown_location());
- if (!package_name.empty())
- package->set_package_name(package_name, this->location());
- }
-
- Named_object* no = package->bindings()->lookup(type_name);
- if (no == NULL)
- no = package->add_type_declaration(type_name, this->location_);
- else if (!no->is_type_declaration() && !no->is_type())
- {
- error_at(this->location_, "imported %<%s.%s%> both type and non-type",
- pkgpath.c_str(), Gogo::message_name(type_name).c_str());
- stream->set_saw_error();
- return Type::make_error_type();
- }
- else
- go_assert(no->package() == package);
-
- if (this->types_[index] == NULL)
- {
- if (no->is_type_declaration())
- {
- // FIXME: It's silly to make a forward declaration every time.
- this->types_[index] = Type::make_forward_declaration(no);
- }
- else
- {
- go_assert(no->is_type());
- this->types_[index] = no->type_value();
- }
- }
-
- // If there is no type definition, then this is just a forward
- // declaration of a type defined in some other file.
- Type* type;
- if (this->match_c_string(">"))
- type = this->types_[index];
- else
- {
- type = this->read_type();
-
- if (no->is_type_declaration())
- {
- // We can define the type now.
-
- no = package->add_type(type_name, type, this->location_);
- Named_type* ntype = no->type_value();
-
- // This type has not yet been imported.
- ntype->clear_is_visible();
-
- if (!type->is_undefined() && type->interface_type() != NULL)
- this->gogo_->record_interface_type(type->interface_type());
-
- type = ntype;
- }
- else if (no->is_type())
- {
- // We have seen this type before. FIXME: it would be a good
- // idea to check that the two imported types are identical,
- // but we have not finalized the methods yet, which means
- // that we can not reliably compare interface types.
- type = no->type_value();
-
- // Don't change the visibility of the existing type.
- }
-
- this->types_[index] = type;
-
- // Read the type methods.
- if (this->match_c_string("\n"))
- {
- this->advance(1);
- while (this->match_c_string(" func"))
- {
- this->advance(1);
- this->import_func(package);
- }
- }
- }
-
- this->require_c_string(">");
-
- return type;
-}
-
-// Register the builtin types.
-
-void
-Import::register_builtin_types(Gogo* gogo)
-{
- this->register_builtin_type(gogo, "int8", BUILTIN_INT8);
- this->register_builtin_type(gogo, "int16", BUILTIN_INT16);
- this->register_builtin_type(gogo, "int32", BUILTIN_INT32);
- this->register_builtin_type(gogo, "int64", BUILTIN_INT64);
- this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8);
- this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16);
- this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32);
- this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
- this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
- this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
- this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
- this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
- this->register_builtin_type(gogo, "int", BUILTIN_INT);
- this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
- this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
- this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
- this->register_builtin_type(gogo, "string", BUILTIN_STRING);
- this->register_builtin_type(gogo, "error", BUILTIN_ERROR);
- this->register_builtin_type(gogo, "byte", BUILTIN_BYTE);
- this->register_builtin_type(gogo, "rune", BUILTIN_RUNE);
-}
-
-// Register a single builtin type.
-
-void
-Import::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code)
-{
- Named_object* named_object = gogo->lookup_global(name);
- go_assert(named_object != NULL && named_object->is_type());
- int index = - static_cast<int>(code);
- go_assert(index > 0
- && static_cast<size_t>(index) < this->builtin_types_.size());
- this->builtin_types_[index] = named_object->type_value();
-}
-
-// Read an identifier from the stream.
-
-std::string
-Import::read_identifier()
-{
- std::string ret;
- Stream* stream = this->stream_;
- int c;
- while (true)
- {
- c = stream->peek_char();
- if (c == -1 || c == ' ' || c == ';')
- break;
- ret += c;
- stream->advance(1);
- }
- return ret;
-}
-
-// Read a name from the stream.
-
-std::string
-Import::read_name()
-{
- std::string ret = this->read_identifier();
- if (ret == "?")
- ret.clear();
- else if (!Lex::is_exported_name(ret))
- ret = '.' + this->package_->pkgpath() + '.' + ret;
- return ret;
-}
-
-// Turn a string into a integer with appropriate error handling.
-
-bool
-Import::string_to_int(const std::string &s, bool is_neg_ok, int* ret)
-{
- char* end;
- long prio = strtol(s.c_str(), &end, 10);
- if (*end != '\0' || prio > 0x7fffffff || (prio < 0 && !is_neg_ok))
- {
- error_at(this->location_, "invalid integer in import data at %d",
- this->stream_->pos());
- this->stream_->set_saw_error();
- return false;
- }
- *ret = prio;
- return true;
-}
-
-// Class Import::Stream.
-
-Import::Stream::Stream()
- : pos_(0), saw_error_(false)
-{
-}
-
-Import::Stream::~Stream()
-{
-}
-
-// Return the next character to come from the stream.
-
-int
-Import::Stream::peek_char()
-{
- const char* read;
- if (!this->do_peek(1, &read))
- return -1;
- // Make sure we return an unsigned char, so that we don't get
- // confused by \xff.
- unsigned char ret = *read;
- return ret;
-}
-
-// Return true if the next LENGTH characters from the stream match
-// BYTES
-
-bool
-Import::Stream::match_bytes(const char* bytes, size_t length)
-{
- const char* read;
- if (!this->do_peek(length, &read))
- return false;
- return memcmp(bytes, read, length) == 0;
-}
-
-// Require that the next LENGTH bytes from the stream match BYTES.
-
-void
-Import::Stream::require_bytes(Location location, const char* bytes,
- size_t length)
-{
- const char* read;
- if (!this->do_peek(length, &read)
- || memcmp(bytes, read, length) != 0)
- {
- if (!this->saw_error_)
- error_at(location, "import error at %d: expected %<%.*s%>",
- this->pos(), static_cast<int>(length), bytes);
- this->saw_error_ = true;
- return;
- }
- this->advance(length);
-}
-
-// Class Stream_from_file.
-
-Stream_from_file::Stream_from_file(int fd)
- : fd_(fd), data_()
-{
- if (lseek(fd, 0, SEEK_SET) != 0)
- {
- error("lseek failed: %m");
- this->set_saw_error();
- }
-}
-
-Stream_from_file::~Stream_from_file()
-{
- close(this->fd_);
-}
-
-// Read next bytes.
-
-bool
-Stream_from_file::do_peek(size_t length, const char** bytes)
-{
- if (this->data_.length() <= length)
- {
- *bytes = this->data_.data();
- return true;
- }
- // Don't bother to handle the general case, since we don't need it.
- go_assert(length < 64);
- char buf[64];
- ssize_t got = read(this->fd_, buf, length);
-
- if (got < 0)
- {
- if (!this->saw_error())
- error("read failed: %m");
- this->set_saw_error();
- return false;
- }
-
- if (lseek(this->fd_, - got, SEEK_CUR) != 0)
- {
- if (!this->saw_error())
- error("lseek failed: %m");
- this->set_saw_error();
- return false;
- }
-
- if (static_cast<size_t>(got) < length)
- return false;
-
- this->data_.assign(buf, got);
-
- *bytes = this->data_.data();
- return true;
-}
-
-// Advance.
-
-void
-Stream_from_file::do_advance(size_t skip)
-{
- if (lseek(this->fd_, skip, SEEK_CUR) != 0)
- {
- if (!this->saw_error())
- error("lseek failed: %m");
- this->set_saw_error();
- }
- if (!this->data_.empty())
- {
- if (this->data_.length() < skip)
- this->data_.erase(0, skip);
- else
- this->data_.clear();
- }
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/import.h b/gcc-4.8.1/gcc/go/gofrontend/import.h
deleted file mode 100644
index c6844cda8..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/import.h
+++ /dev/null
@@ -1,359 +0,0 @@
-// import.h -- Go frontend import declarations. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_IMPORT_H
-#define GO_IMPORT_H
-
-#include "export.h"
-#include "go-linemap.h"
-
-class Gogo;
-class Package;
-class Type;
-class Named_object;
-class Named_type;
-class Expression;
-
-// This class manages importing Go declarations.
-
-class Import
-{
- public:
- // The Stream class is an interface used to read the data. The
- // caller should instantiate a child of this class.
- class Stream
- {
- public:
- Stream();
- virtual ~Stream();
-
- // Return whether we have seen an error.
- bool
- saw_error() const
- { return this->saw_error_; }
-
- // Record that we've seen an error.
- void
- set_saw_error()
- { this->saw_error_ = true; }
-
- // Return the next character (a value from 0 to 0xff) without
- // advancing. Returns -1 at end of stream.
- int
- peek_char();
-
- // Look for LENGTH characters, setting *BYTES to point to them.
- // Returns false if the bytes are not available. Does not
- // advance.
- bool
- peek(size_t length, const char** bytes)
- { return this->do_peek(length, bytes); }
-
- // Return the next character (a value from 0 to 0xff) and advance
- // the read position by 1. Returns -1 at end of stream.
- int
- get_char()
- {
- int c = this->peek_char();
- this->advance(1);
- return c;
- }
-
- // Return true if at the end of the stream.
- bool
- at_eof()
- { return this->peek_char() == -1; }
-
- // Return true if the next bytes match STR.
- bool
- match_c_string(const char* str)
- { return this->match_bytes(str, strlen(str)); }
-
- // Return true if the next LENGTH bytes match BYTES.
- bool
- match_bytes(const char* bytes, size_t length);
-
- // Give an error if the next bytes do not match STR. Advance the
- // read position by the length of STR.
- void
- require_c_string(Location location, const char* str)
- { this->require_bytes(location, str, strlen(str)); }
-
- // Given an error if the next LENGTH bytes do not match BYTES.
- // Advance the read position by LENGTH.
- void
- require_bytes(Location, const char* bytes, size_t length);
-
- // Advance the read position by SKIP bytes.
- void
- advance(size_t skip)
- {
- this->do_advance(skip);
- this->pos_ += skip;
- }
-
- // Return the current read position. This returns int because it
- // is more convenient in error reporting. FIXME.
- int
- pos()
- { return static_cast<int>(this->pos_); }
-
- protected:
- // This function should set *BYTES to point to a buffer holding
- // the LENGTH bytes at the current read position. It should
- // return false if the bytes are not available. This should not
- // change the current read position.
- virtual bool
- do_peek(size_t length, const char** bytes) = 0;
-
- // This function should advance the current read position LENGTH
- // bytes.
- virtual void
- do_advance(size_t skip) = 0;
-
- private:
- // The current read position.
- size_t pos_;
- // True if we've seen an error reading from this stream.
- bool saw_error_;
- };
-
- // Find import data. This searches the file system for FILENAME and
- // returns a pointer to a Stream object to read the data that it
- // exports. LOCATION is the location of the import statement.
- // RELATIVE_IMPORT_PATH is used as a prefix for a relative import.
- static Stream*
- open_package(const std::string& filename, Location location,
- const std::string& relative_import_path);
-
- // Constructor.
- Import(Stream*, Location);
-
- // Register the builtin types.
- void
- register_builtin_types(Gogo*);
-
- // Import everything defined in the stream. LOCAL_NAME is the local
- // name to be used for bindings; if it is the string "." then
- // bindings should be inserted in the global scope. If LOCAL_NAME
- // is the empty string then the name of the package itself is the
- // local name. This returns the imported package, or NULL on error.
- Package*
- import(Gogo*, const std::string& local_name, bool is_local_name_exported);
-
- // The location of the import statement.
- Location
- location() const
- { return this->location_; }
-
- // Return the next character.
- int
- peek_char()
- { return this->stream_->peek_char(); }
-
- // Return the next character and advance.
- int
- get_char()
- { return this->stream_->get_char(); }
-
- // Return true at the end of the stream.
- bool
- at_eof()
- { return this->stream_->at_eof(); }
-
- // Return whether the next bytes match STR.
- bool
- match_c_string(const char* str)
- { return this->stream_->match_c_string(str); }
-
- // Require that the next bytes match STR.
- void
- require_c_string(const char* str)
- { this->stream_->require_c_string(this->location_, str); }
-
- // Advance the stream SKIP bytes.
- void
- advance(size_t skip)
- { this->stream_->advance(skip); }
-
- // Read an identifier.
- std::string
- read_identifier();
-
- // Read a name. This is like read_identifier, except that a "?" is
- // returned as an empty string. This matches Export::write_name.
- std::string
- read_name();
-
- // Read a type.
- Type*
- read_type();
-
- private:
- static Stream*
- try_package_in_directory(const std::string&, Location);
-
- static int
- try_suffixes(std::string*);
-
- static Stream*
- find_export_data(const std::string& filename, int fd, Location);
-
- static Stream*
- find_object_export_data(const std::string& filename, int fd,
- off_t offset, Location);
-
- static const int archive_magic_len = 8;
-
- static bool
- is_archive_magic(const char*);
-
- static Stream*
- find_archive_export_data(const std::string& filename, int fd,
- Location);
-
- // Read an import line.
- void
- read_one_import();
-
- // Read the import control functions.
- void
- read_import_init_fns(Gogo*);
-
- // Import a constant.
- void
- import_const();
-
- // Import a type.
- void
- import_type();
-
- // Import a variable.
- void
- import_var();
-
- // Import a function.
- Named_object*
- import_func(Package*);
-
- // Register a single builtin type.
- void
- register_builtin_type(Gogo*, const char* name, Builtin_code);
-
- // Get an integer from a string.
- bool
- string_to_int(const std::string&, bool is_neg_ok, int* ret);
-
- // The general IR.
- Gogo* gogo_;
- // The stream from which to read import data.
- Stream* stream_;
- // The location of the import statement we are processing.
- Location location_;
- // The package we are importing.
- Package* package_;
- // Whether to add new objects to the global scope, rather than to a
- // package scope.
- bool add_to_globals_;
- // Mapping from negated builtin type codes to Type structures.
- std::vector<Named_type*> builtin_types_;
- // Mapping from exported type codes to Type structures.
- std::vector<Type*> types_;
-};
-
-// Read import data from a string.
-
-class Stream_from_string : public Import::Stream
-{
- public:
- Stream_from_string(const std::string& str)
- : str_(str), pos_(0)
- { }
-
- protected:
- bool
- do_peek(size_t length, const char** bytes)
- {
- if (this->pos_ + length > this->str_.length())
- return false;
- *bytes = this->str_.data() + this->pos_;
- return true;
- }
-
- void
- do_advance(size_t len)
- { this->pos_ += len; }
-
- private:
- // The string of data we are reading.
- std::string str_;
- // The current position within the string.
- size_t pos_;
-};
-
-// Read import data from a buffer allocated using malloc.
-
-class Stream_from_buffer : public Import::Stream
-{
- public:
- Stream_from_buffer(char* buf, size_t length)
- : buf_(buf), length_(length), pos_(0)
- { }
-
- ~Stream_from_buffer()
- { free(this->buf_); }
-
- protected:
- bool
- do_peek(size_t length, const char** bytes)
- {
- if (this->pos_ + length > this->length_)
- return false;
- *bytes = this->buf_ + this->pos_;
- return true;
- }
-
- void
- do_advance(size_t len)
- { this->pos_ += len; }
-
- private:
- // The data we are reading.
- char* buf_;
- // The length of the buffer.
- size_t length_;
- // The current position within the buffer.
- size_t pos_;
-};
-
-// Read import data from an open file descriptor.
-
-class Stream_from_file : public Import::Stream
-{
- public:
- Stream_from_file(int fd);
-
- ~Stream_from_file();
-
- protected:
- bool
- do_peek(size_t, const char**);
-
- void
- do_advance(size_t);
-
- private:
- // No copying.
- Stream_from_file(const Stream_from_file&);
- Stream_from_file& operator=(const Stream_from_file&);
-
- // The file descriptor.
- int fd_;
- // Data read from the file.
- std::string data_;
-};
-
-#endif // !defined(GO_IMPORT_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/lex.cc b/gcc-4.8.1/gcc/go/gofrontend/lex.cc
deleted file mode 100644
index 22a1f6e2a..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/lex.cc
+++ /dev/null
@@ -1,2419 +0,0 @@
-// lex.cc -- Go frontend lexer.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "lex.h"
-
-// Manage mapping from keywords to the Keyword codes.
-
-class Keywords
-{
- public:
- // The structure which maps keywords to codes.
- struct Mapping
- {
- // Keyword string.
- const char* keystring;
- // Keyword code.
- Keyword keycode;
- };
-
- // Return the parsecode corresponding to KEYSTRING, or
- // KEYWORD_INVALID if it is not a keyword.
- Keyword
- keyword_to_code(const char* keyword, size_t len) const;
-
- // Return the string for a keyword.
- const char*
- keyword_to_string(Keyword) const;
-
- private:
- static const Mapping mapping_[];
- static const int count_;
-};
-
-// Mapping from keyword string to keyword code. This array must be
-// kept in sorted order, and the order must match the Keyword enum.
-// Strings are looked up using bsearch.
-
-const Keywords::Mapping
-Keywords::mapping_[] =
-{
- { NULL, KEYWORD_INVALID },
- { "__asm__", KEYWORD_ASM },
- { "break", KEYWORD_BREAK },
- { "case", KEYWORD_CASE },
- { "chan", KEYWORD_CHAN },
- { "const", KEYWORD_CONST },
- { "continue", KEYWORD_CONTINUE },
- { "default", KEYWORD_DEFAULT },
- { "defer", KEYWORD_DEFER },
- { "else", KEYWORD_ELSE },
- { "fallthrough", KEYWORD_FALLTHROUGH },
- { "for", KEYWORD_FOR },
- { "func", KEYWORD_FUNC },
- { "go", KEYWORD_GO },
- { "goto", KEYWORD_GOTO },
- { "if", KEYWORD_IF },
- { "import", KEYWORD_IMPORT },
- { "interface", KEYWORD_INTERFACE },
- { "map", KEYWORD_MAP },
- { "package", KEYWORD_PACKAGE },
- { "range", KEYWORD_RANGE },
- { "return", KEYWORD_RETURN },
- { "select", KEYWORD_SELECT },
- { "struct", KEYWORD_STRUCT },
- { "switch", KEYWORD_SWITCH },
- { "type", KEYWORD_TYPE },
- { "var", KEYWORD_VAR }
-};
-
-// Number of entries in the map.
-
-const int Keywords::count_ =
- sizeof(Keywords::mapping_) / sizeof(Keywords::mapping_[0]);
-
-// Comparison function passed to bsearch.
-
-extern "C"
-{
-
-struct Keywords_search_key
-{
- const char* str;
- size_t len;
-};
-
-static int
-keyword_compare(const void* keyv, const void* mapv)
-{
- const Keywords_search_key* key =
- static_cast<const Keywords_search_key*>(keyv);
- const Keywords::Mapping* map =
- static_cast<const Keywords::Mapping*>(mapv);
- if (map->keystring == NULL)
- return 1;
- int i = strncmp(key->str, map->keystring, key->len);
- if (i != 0)
- return i;
- if (map->keystring[key->len] != '\0')
- return -1;
- return 0;
-}
-
-} // End extern "C".
-
-// Convert a string to a keyword code. Return KEYWORD_INVALID if the
-// string is not a keyword.
-
-Keyword
-Keywords::keyword_to_code(const char* keyword, size_t len) const
-{
- Keywords_search_key key;
- key.str = keyword;
- key.len = len;
- void* mapv = bsearch(&key,
- this->mapping_,
- this->count_,
- sizeof(this->mapping_[0]),
- keyword_compare);
- if (mapv == NULL)
- return KEYWORD_INVALID;
- Mapping* map = static_cast<Mapping*>(mapv);
- return map->keycode;
-}
-
-// Convert a keyword code to a string.
-
-const char*
-Keywords::keyword_to_string(Keyword code) const
-{
- go_assert(code > KEYWORD_INVALID && code < this->count_);
- const Mapping* map = &this->mapping_[code];
- go_assert(map->keycode == code);
- return map->keystring;
-}
-
-// There is one instance of the Keywords class.
-
-static Keywords keywords;
-
-// Class Token.
-
-// Make a general token.
-
-Token::Token(Classification classification, Location location)
- : classification_(classification), location_(location)
-{
-}
-
-// Destroy a token.
-
-Token::~Token()
-{
- this->clear();
-}
-
-// Clear a token--release memory.
-
-void
-Token::clear()
-{
- if (this->classification_ == TOKEN_INTEGER
- || this->classification_ == TOKEN_CHARACTER)
- mpz_clear(this->u_.integer_value);
- else if (this->classification_ == TOKEN_FLOAT
- || this->classification_ == TOKEN_IMAGINARY)
- mpfr_clear(this->u_.float_value);
-}
-
-// Construct a token.
-
-Token::Token(const Token& tok)
- : classification_(tok.classification_), location_(tok.location_)
-{
- switch (this->classification_)
- {
- case TOKEN_INVALID:
- case TOKEN_EOF:
- break;
- case TOKEN_KEYWORD:
- this->u_.keyword = tok.u_.keyword;
- break;
- case TOKEN_IDENTIFIER:
- case TOKEN_STRING:
- this->u_.string_value = tok.u_.string_value;
- break;
- case TOKEN_OPERATOR:
- this->u_.op = tok.u_.op;
- break;
- case TOKEN_CHARACTER:
- case TOKEN_INTEGER:
- mpz_init_set(this->u_.integer_value, tok.u_.integer_value);
- break;
- case TOKEN_FLOAT:
- case TOKEN_IMAGINARY:
- mpfr_init_set(this->u_.float_value, tok.u_.float_value, GMP_RNDN);
- break;
- default:
- go_unreachable();
- }
-}
-
-// Assign to a token.
-
-Token&
-Token::operator=(const Token& tok)
-{
- this->clear();
- this->classification_ = tok.classification_;
- this->location_ = tok.location_;
- switch (tok.classification_)
- {
- case TOKEN_INVALID:
- case TOKEN_EOF:
- break;
- case TOKEN_KEYWORD:
- this->u_.keyword = tok.u_.keyword;
- break;
- case TOKEN_IDENTIFIER:
- this->u_.identifier_value.name = tok.u_.identifier_value.name;
- this->u_.identifier_value.is_exported =
- tok.u_.identifier_value.is_exported;
- break;
- case TOKEN_STRING:
- this->u_.string_value = tok.u_.string_value;
- break;
- case TOKEN_OPERATOR:
- this->u_.op = tok.u_.op;
- break;
- case TOKEN_CHARACTER:
- case TOKEN_INTEGER:
- mpz_init_set(this->u_.integer_value, tok.u_.integer_value);
- break;
- case TOKEN_FLOAT:
- case TOKEN_IMAGINARY:
- mpfr_init_set(this->u_.float_value, tok.u_.float_value, GMP_RNDN);
- break;
- default:
- go_unreachable();
- }
- return *this;
-}
-
-// Print the token for debugging.
-
-void
-Token::print(FILE* file) const
-{
- switch (this->classification_)
- {
- case TOKEN_INVALID:
- fprintf(file, "invalid");
- break;
- case TOKEN_EOF:
- fprintf(file, "EOF");
- break;
- case TOKEN_KEYWORD:
- fprintf(file, "keyword %s", keywords.keyword_to_string(this->u_.keyword));
- break;
- case TOKEN_IDENTIFIER:
- fprintf(file, "identifier \"%s\"", this->u_.string_value->c_str());
- break;
- case TOKEN_STRING:
- fprintf(file, "quoted string \"%s\"", this->u_.string_value->c_str());
- break;
- case TOKEN_CHARACTER:
- fprintf(file, "character ");
- mpz_out_str(file, 10, this->u_.integer_value);
- break;
- case TOKEN_INTEGER:
- fprintf(file, "integer ");
- mpz_out_str(file, 10, this->u_.integer_value);
- break;
- case TOKEN_FLOAT:
- fprintf(file, "float ");
- mpfr_out_str(file, 10, 0, this->u_.float_value, GMP_RNDN);
- break;
- case TOKEN_IMAGINARY:
- fprintf(file, "imaginary ");
- mpfr_out_str(file, 10, 0, this->u_.float_value, GMP_RNDN);
- break;
- case TOKEN_OPERATOR:
- fprintf(file, "operator ");
- switch (this->u_.op)
- {
- case OPERATOR_INVALID:
- fprintf(file, "invalid");
- break;
- case OPERATOR_OROR:
- fprintf(file, "||");
- break;
- case OPERATOR_ANDAND:
- fprintf(file, "&&");
- break;
- case OPERATOR_EQEQ:
- fprintf(file, "==");
- break;
- case OPERATOR_NOTEQ:
- fprintf(file, "!=");
- break;
- case OPERATOR_LT:
- fprintf(file, "<");
- break;
- case OPERATOR_LE:
- fprintf(file, "<=");
- break;
- case OPERATOR_GT:
- fprintf(file, ">");
- break;
- case OPERATOR_GE:
- fprintf(file, ">=");
- break;
- case OPERATOR_PLUS:
- fprintf(file, "+");
- break;
- case OPERATOR_MINUS:
- fprintf(file, "-");
- break;
- case OPERATOR_OR:
- fprintf(file, "|");
- break;
- case OPERATOR_XOR:
- fprintf(file, "^");
- break;
- case OPERATOR_MULT:
- fprintf(file, "*");
- break;
- case OPERATOR_DIV:
- fprintf(file, "/");
- break;
- case OPERATOR_MOD:
- fprintf(file, "%%");
- break;
- case OPERATOR_LSHIFT:
- fprintf(file, "<<");
- break;
- case OPERATOR_RSHIFT:
- fprintf(file, ">>");
- break;
- case OPERATOR_AND:
- fprintf(file, "&");
- break;
- case OPERATOR_BITCLEAR:
- fprintf(file, "&^");
- break;
- case OPERATOR_NOT:
- fprintf(file, "!");
- break;
- case OPERATOR_CHANOP:
- fprintf(file, "<-");
- break;
- case OPERATOR_EQ:
- fprintf(file, "=");
- break;
- case OPERATOR_PLUSEQ:
- fprintf(file, "+=");
- break;
- case OPERATOR_MINUSEQ:
- fprintf(file, "-=");
- break;
- case OPERATOR_OREQ:
- fprintf(file, "|=");
- break;
- case OPERATOR_XOREQ:
- fprintf(file, "^=");
- break;
- case OPERATOR_MULTEQ:
- fprintf(file, "*=");
- break;
- case OPERATOR_DIVEQ:
- fprintf(file, "/=");
- break;
- case OPERATOR_MODEQ:
- fprintf(file, "%%=");
- break;
- case OPERATOR_LSHIFTEQ:
- fprintf(file, "<<=");
- break;
- case OPERATOR_RSHIFTEQ:
- fprintf(file, ">>=");
- break;
- case OPERATOR_ANDEQ:
- fprintf(file, "&=");
- break;
- case OPERATOR_BITCLEAREQ:
- fprintf(file, "&^=");
- break;
- case OPERATOR_PLUSPLUS:
- fprintf(file, "++");
- break;
- case OPERATOR_MINUSMINUS:
- fprintf(file, "--");
- break;
- case OPERATOR_COLON:
- fprintf(file, ":");
- break;
- case OPERATOR_COLONEQ:
- fprintf(file, ":=");
- break;
- case OPERATOR_SEMICOLON:
- fprintf(file, ";");
- break;
- case OPERATOR_DOT:
- fprintf(file, ".");
- break;
- case OPERATOR_COMMA:
- fprintf(file, ",");
- break;
- case OPERATOR_LPAREN:
- fprintf(file, "(");
- break;
- case OPERATOR_RPAREN:
- fprintf(file, ")");
- break;
- case OPERATOR_LCURLY:
- fprintf(file, "{");
- break;
- case OPERATOR_RCURLY:
- fprintf(file, "}");
- break;
- case OPERATOR_LSQUARE:
- fprintf(file, "[");
- break;
- case OPERATOR_RSQUARE:
- fprintf(file, "]");
- break;
- default:
- go_unreachable();
- }
- break;
- default:
- go_unreachable();
- }
-}
-
-// Class Lex.
-
-Lex::Lex(const char* input_file_name, FILE* input_file, Linemap* linemap)
- : input_file_name_(input_file_name), input_file_(input_file),
- linemap_(linemap), linebuf_(NULL), linebufsize_(120), linesize_(0),
- lineoff_(0), lineno_(0), add_semi_at_eol_(false), saw_nointerface_(false),
- extern_()
-{
- this->linebuf_ = new char[this->linebufsize_];
- this->linemap_->start_file(input_file_name, 0);
-}
-
-Lex::~Lex()
-{
- delete[] this->linebuf_;
-}
-
-// Read a new line from the file.
-
-ssize_t
-Lex::get_line()
-{
- char* buf = this->linebuf_;
- size_t size = this->linebufsize_;
-
- FILE* file = this->input_file_;
- size_t cur = 0;
- while (true)
- {
- int c = getc(file);
- if (c == EOF)
- {
- if (cur == 0)
- return -1;
- break;
- }
- if (cur + 1 >= size)
- {
- size_t ns = 2 * size + 1;
- if (ns < size || static_cast<ssize_t>(ns) < 0)
- error_at(this->location(), "out of memory");
- char* nb = new char[ns];
- memcpy(nb, buf, cur);
- delete[] buf;
- buf = nb;
- size = ns;
- }
- buf[cur] = c;
- ++cur;
-
- if (c == '\n')
- break;
- }
-
- buf[cur] = '\0';
-
- this->linebuf_ = buf;
- this->linebufsize_ = size;
-
- return cur;
-}
-
-// See if we need to read a new line. Return true if there is a new
-// line, false if we are at EOF.
-
-bool
-Lex::require_line()
-{
- if (this->lineoff_ < this->linesize_)
- return true;
-
- ssize_t got = this->get_line();
- if (got < 0)
- return false;
- ++this->lineno_;
- this->linesize_= got;
- this->lineoff_ = 0;
-
- this->linemap_->start_line(this->lineno_, this->linesize_);
-
- return true;
-}
-
-// Get the current location.
-
-Location
-Lex::location() const
-{
- return this->linemap_->get_location(this->lineoff_ + 1);
-}
-
-// Get a location slightly before the current one. This is used for
-// slightly more efficient handling of operator tokens.
-
-Location
-Lex::earlier_location(int chars) const
-{
- return this->linemap_->get_location(this->lineoff_ + 1 - chars);
-}
-
-// Get the next token.
-
-Token
-Lex::next_token()
-{
- bool saw_cpp_comment = false;
- while (true)
- {
- if (!this->require_line())
- {
- bool add_semi_at_eol = this->add_semi_at_eol_;
- this->add_semi_at_eol_ = false;
- if (add_semi_at_eol)
- return this->make_operator(OPERATOR_SEMICOLON, 1);
- return this->make_eof_token();
- }
-
- if (!saw_cpp_comment)
- this->extern_.clear();
- saw_cpp_comment = false;
-
- const char* p = this->linebuf_ + this->lineoff_;
- const char* pend = this->linebuf_ + this->linesize_;
-
- while (p < pend)
- {
- unsigned char cc = *p;
- switch (cc)
- {
- case ' ': case '\t': case '\r':
- ++p;
- // Skip whitespace quickly.
- while (*p == ' ' || *p == '\t' || *p == '\r')
- ++p;
- break;
-
- case '\n':
- {
- ++p;
- bool add_semi_at_eol = this->add_semi_at_eol_;
- this->add_semi_at_eol_ = false;
- if (add_semi_at_eol)
- {
- this->lineoff_ = p - this->linebuf_;
- return this->make_operator(OPERATOR_SEMICOLON, 1);
- }
- }
- break;
-
- case '/':
- if (p[1] == '/')
- {
- this->lineoff_ = p + 2 - this->linebuf_;
- this->skip_cpp_comment();
- p = pend;
- if (p[-1] == '\n' && this->add_semi_at_eol_)
- --p;
- saw_cpp_comment = true;
- }
- else if (p[1] == '*')
- {
- this->lineoff_ = p - this->linebuf_;
- Location location = this->location();
- if (!this->skip_c_comment())
- return Token::make_invalid_token(location);
- p = this->linebuf_ + this->lineoff_;
- pend = this->linebuf_ + this->linesize_;
- }
- else if (p[1] == '=')
- {
- this->add_semi_at_eol_ = false;
- this->lineoff_ = p + 2 - this->linebuf_;
- return this->make_operator(OPERATOR_DIVEQ, 2);
- }
- else
- {
- this->add_semi_at_eol_ = false;
- this->lineoff_ = p + 1 - this->linebuf_;
- return this->make_operator(OPERATOR_DIV, 1);
- }
- break;
-
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
- case 's': case 't': case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case '_':
- this->lineoff_ = p - this->linebuf_;
- return this->gather_identifier();
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- this->add_semi_at_eol_ = true;
- this->lineoff_ = p - this->linebuf_;
- return this->gather_number();
-
- case '\'':
- this->add_semi_at_eol_ = true;
- this->lineoff_ = p - this->linebuf_;
- return this->gather_character();
-
- case '"':
- this->add_semi_at_eol_ = true;
- this->lineoff_ = p - this->linebuf_;
- return this->gather_string();
-
- case '`':
- this->add_semi_at_eol_ = true;
- this->lineoff_ = p - this->linebuf_;
- return this->gather_raw_string();
-
- case '<':
- case '>':
- case '&':
- if (p + 2 < pend)
- {
- this->add_semi_at_eol_ = false;
- Operator op = this->three_character_operator(cc, p[1], p[2]);
- if (op != OPERATOR_INVALID)
- {
- this->lineoff_ = p + 3 - this->linebuf_;
- return this->make_operator(op, 3);
- }
- }
- // Fall through.
- case '|':
- case '=':
- case '!':
- case '+':
- case '-':
- case '^':
- case '*':
- // '/' handled above.
- case '%':
- case ':':
- case ';':
- case ',':
- case '(': case ')':
- case '{': case '}':
- case '[': case ']':
- {
- this->add_semi_at_eol_ = false;
- Operator op = this->two_character_operator(cc, p[1]);
- int chars;
- if (op != OPERATOR_INVALID)
- {
- ++p;
- chars = 2;
- }
- else
- {
- op = this->one_character_operator(cc);
- chars = 1;
- }
- this->lineoff_ = p + 1 - this->linebuf_;
- return this->make_operator(op, chars);
- }
-
- case '.':
- if (p[1] >= '0' && p[1] <= '9')
- {
- this->add_semi_at_eol_ = true;
- this->lineoff_ = p - this->linebuf_;
- return this->gather_number();
- }
- if (p[1] == '.' && p[2] == '.')
- {
- this->add_semi_at_eol_ = false;
- this->lineoff_ = p + 3 - this->linebuf_;
- return this->make_operator(OPERATOR_ELLIPSIS, 3);
- }
- this->add_semi_at_eol_ = false;
- this->lineoff_ = p + 1 - this->linebuf_;
- return this->make_operator(OPERATOR_DOT, 1);
-
- default:
- {
- unsigned int ci;
- bool issued_error;
- this->lineoff_ = p - this->linebuf_;
- const char *pnext = this->advance_one_utf8_char(p, &ci,
- &issued_error);
-
- // Ignore byte order mark at start of file.
- if (ci == 0xfeff)
- {
- p = pnext;
- break;
- }
-
- if (Lex::is_unicode_letter(ci))
- return this->gather_identifier();
-
- if (!issued_error)
- error_at(this->location(),
- "invalid character 0x%x in input file",
- ci);
-
- p = pend;
-
- break;
- }
- }
- }
-
- this->lineoff_ = p - this->linebuf_;
- }
-}
-
-// Fetch one UTF-8 character from a string. Set *VALUE to the value.
-// Return the number of bytes read from the string. Returns 0 if the
-// string does not point to a valid UTF-8 character.
-
-int
-Lex::fetch_char(const char* p, unsigned int* value)
-{
- unsigned char c = *p;
- if (c <= 0x7f)
- {
- *value = c;
- return 1;
- }
- else if ((c & 0xe0) == 0xc0
- && (p[1] & 0xc0) == 0x80)
- {
- *value = (((c & 0x1f) << 6)
- + (p[1] & 0x3f));
- if (*value <= 0x7f)
- {
- *value = 0xfffd;
- return 0;
- }
- return 2;
- }
- else if ((c & 0xf0) == 0xe0
- && (p[1] & 0xc0) == 0x80
- && (p[2] & 0xc0) == 0x80)
- {
- *value = (((c & 0xf) << 12)
- + ((p[1] & 0x3f) << 6)
- + (p[2] & 0x3f));
- if (*value <= 0x7ff)
- {
- *value = 0xfffd;
- return 0;
- }
- return 3;
- }
- else if ((c & 0xf8) == 0xf0
- && (p[1] & 0xc0) == 0x80
- && (p[2] & 0xc0) == 0x80
- && (p[3] & 0xc0) == 0x80)
- {
- *value = (((c & 0x7) << 18)
- + ((p[1] & 0x3f) << 12)
- + ((p[2] & 0x3f) << 6)
- + (p[3] & 0x3f));
- if (*value <= 0xffff)
- {
- *value = 0xfffd;
- return 0;
- }
- return 4;
- }
- else
- {
- /* Invalid encoding. Return the Unicode replacement
- character. */
- *value = 0xfffd;
- return 0;
- }
-}
-
-// Advance one UTF-8 character. Return the pointer beyond the
-// character. Set *VALUE to the value. Set *ISSUED_ERROR if an error
-// was issued.
-
-const char*
-Lex::advance_one_utf8_char(const char* p, unsigned int* value,
- bool* issued_error)
-{
- *issued_error = false;
-
- if (*p == '\0')
- {
- error_at(this->location(), "invalid NUL byte");
- *issued_error = true;
- *value = 0;
- return p + 1;
- }
-
- int adv = Lex::fetch_char(p, value);
- if (adv == 0)
- {
- error_at(this->location(), "invalid UTF-8 encoding");
- *issued_error = true;
- return p + 1;
- }
-
- // Warn about byte order mark, except at start of file.
- if (*value == 0xfeff && (this->lineno_ != 1 || this->lineoff_ != 0))
- {
- error_at(this->location(), "Unicode (UTF-8) BOM in middle of file");
- *issued_error = true;
- }
-
- return p + adv;
-}
-
-// Pick up an identifier.
-
-Token
-Lex::gather_identifier()
-{
- const char* pstart = this->linebuf_ + this->lineoff_;
- const char* p = pstart;
- const char* pend = this->linebuf_ + this->linesize_;
- bool is_first = true;
- bool is_exported = false;
- bool has_non_ascii_char = false;
- std::string buf;
- while (p < pend)
- {
- unsigned char cc = *p;
- if (cc <= 0x7f)
- {
- if ((cc < 'A' || cc > 'Z')
- && (cc < 'a' || cc > 'z')
- && cc != '_'
- && (cc < '0' || cc > '9'))
- break;
- ++p;
- if (is_first)
- {
- is_exported = cc >= 'A' && cc <= 'Z';
- is_first = false;
- }
- if (has_non_ascii_char)
- buf.push_back(cc);
- }
- else
- {
- unsigned int ci;
- bool issued_error;
- this->lineoff_ = p - this->linebuf_;
- const char* pnext = this->advance_one_utf8_char(p, &ci,
- &issued_error);
- bool is_invalid = false;
- if (!Lex::is_unicode_letter(ci) && !Lex::is_unicode_digit(ci))
- {
- // There is no valid place for a non-ASCII character
- // other than an identifier, so we get better error
- // handling behaviour if we swallow this character after
- // giving an error.
- if (!issued_error)
- error_at(this->location(),
- "invalid character 0x%x in identifier",
- ci);
- is_invalid = true;
- }
- if (is_first)
- {
- is_exported = Lex::is_unicode_uppercase(ci);
- is_first = false;
- }
- if (!has_non_ascii_char)
- {
- buf.assign(pstart, p - pstart);
- has_non_ascii_char = true;
- }
- if (is_invalid && !Lex::is_invalid_identifier(buf))
- buf.append("$INVALID$");
- buf.append(p, pnext - p);
- p = pnext;
- }
- }
- Location location = this->location();
- this->add_semi_at_eol_ = true;
- this->lineoff_ = p - this->linebuf_;
- if (has_non_ascii_char)
- return Token::make_identifier_token(buf, is_exported, location);
- else
- {
- Keyword code = keywords.keyword_to_code(pstart, p - pstart);
- if (code == KEYWORD_INVALID)
- return Token::make_identifier_token(std::string(pstart, p - pstart),
- is_exported, location);
- else
- {
- switch (code)
- {
- case KEYWORD_BREAK:
- case KEYWORD_CONTINUE:
- case KEYWORD_FALLTHROUGH:
- case KEYWORD_RETURN:
- break;
- default:
- this->add_semi_at_eol_ = false;
- break;
- }
- return Token::make_keyword_token(code, location);
- }
- }
-}
-
-// Return whether C is a hex digit.
-
-bool
-Lex::is_hex_digit(char c)
-{
- return ((c >= '0' && c <= '9')
- || (c >= 'A' && c <= 'F')
- || (c >= 'a' && c <= 'f'));
-}
-
-// Return whether an exponent could start at P.
-
-bool
-Lex::could_be_exponent(const char* p, const char* pend)
-{
- if (*p != 'e' && *p != 'E')
- return false;
- ++p;
- if (p >= pend)
- return false;
- if (*p == '+' || *p == '-')
- {
- ++p;
- if (p >= pend)
- return false;
- }
- return *p >= '0' && *p <= '9';
-}
-
-// Pick up a number.
-
-Token
-Lex::gather_number()
-{
- const char* pstart = this->linebuf_ + this->lineoff_;
- const char* p = pstart;
- const char* pend = this->linebuf_ + this->linesize_;
-
- Location location = this->location();
-
- bool neg = false;
- if (*p == '+')
- ++p;
- else if (*p == '-')
- {
- ++p;
- neg = true;
- }
-
- const char* pnum = p;
- if (*p == '0')
- {
- int base;
- if ((p[1] == 'x' || p[1] == 'X')
- && Lex::is_hex_digit(p[2]))
- {
- base = 16;
- p += 2;
- pnum = p;
- while (p < pend)
- {
- if (!Lex::is_hex_digit(*p))
- break;
- ++p;
- }
- }
- else
- {
- base = 8;
- pnum = p;
- while (p < pend)
- {
- if (*p < '0' || *p > '7')
- break;
- ++p;
- }
- }
-
- // A partial token that looks like an octal literal might actually be the
- // beginning of a floating-point or imaginary literal.
- if (base == 16 || (*p != '.' && *p != 'i' && !Lex::could_be_exponent(p, pend)))
- {
- std::string s(pnum, p - pnum);
- mpz_t val;
- int r = mpz_init_set_str(val, s.c_str(), base);
- go_assert(r == 0);
-
- if (neg)
- mpz_neg(val, val);
-
- this->lineoff_ = p - this->linebuf_;
- Token ret = Token::make_integer_token(val, location);
- mpz_clear(val);
- return ret;
- }
- }
-
- while (p < pend)
- {
- if (*p < '0' || *p > '9')
- break;
- ++p;
- }
-
- if (*p != '.' && *p != 'i' && !Lex::could_be_exponent(p, pend))
- {
- std::string s(pnum, p - pnum);
- mpz_t val;
- int r = mpz_init_set_str(val, s.c_str(), 10);
- go_assert(r == 0);
-
- if (neg)
- mpz_neg(val, val);
-
- this->lineoff_ = p - this->linebuf_;
- Token ret = Token::make_integer_token(val, location);
- mpz_clear(val);
- return ret;
- }
-
- if (*p != 'i')
- {
- bool dot = *p == '.';
-
- ++p;
-
- if (!dot)
- {
- if (*p == '+' || *p == '-')
- ++p;
- }
-
- while (p < pend)
- {
- if (*p < '0' || *p > '9')
- break;
- ++p;
- }
-
- if (dot && Lex::could_be_exponent(p, pend))
- {
- ++p;
- if (*p == '+' || *p == '-')
- ++p;
- while (p < pend)
- {
- if (*p < '0' || *p > '9')
- break;
- ++p;
- }
- }
- }
-
- std::string s(pnum, p - pnum);
- mpfr_t val;
- int r = mpfr_init_set_str(val, s.c_str(), 10, GMP_RNDN);
- go_assert(r == 0);
-
- if (neg)
- mpfr_neg(val, val, GMP_RNDN);
-
- bool is_imaginary = *p == 'i';
- if (is_imaginary)
- ++p;
-
- this->lineoff_ = p - this->linebuf_;
- if (is_imaginary)
- {
- Token ret = Token::make_imaginary_token(val, location);
- mpfr_clear(val);
- return ret;
- }
- else
- {
- Token ret = Token::make_float_token(val, location);
- mpfr_clear(val);
- return ret;
- }
-}
-
-// Advance one character, possibly escaped. Return the pointer beyond
-// the character. Set *VALUE to the character. Set *IS_CHARACTER if
-// this is a character (e.g., 'a' or '\u1234') rather than a byte
-// value (e.g., '\001').
-
-const char*
-Lex::advance_one_char(const char* p, bool is_single_quote, unsigned int* value,
- bool* is_character)
-{
- *value = 0;
- *is_character = true;
- if (*p != '\\')
- {
- bool issued_error;
- const char* ret = this->advance_one_utf8_char(p, value, &issued_error);
- if (is_single_quote
- && (*value == '\'' || *value == '\n')
- && !issued_error)
- error_at(this->location(), "invalid character literal");
- return ret;
- }
- else
- {
- ++p;
- switch (*p)
- {
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- *is_character = false;
- if (p[1] >= '0' && p[1] <= '7'
- && p[2] >= '0' && p[2] <= '7')
- {
- *value = ((Lex::octal_value(p[0]) << 6)
- + (Lex::octal_value(p[1]) << 3)
- + Lex::octal_value(p[2]));
- if (*value > 255)
- {
- error_at(this->location(), "invalid octal constant");
- *value = 255;
- }
- return p + 3;
- }
- error_at(this->location(), "invalid octal character");
- return (p[1] >= '0' && p[1] <= '7'
- ? p + 2
- : p + 1);
-
- case 'x':
- case 'X':
- *is_character = false;
- if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2]))
- {
- *value = (hex_value(p[1]) << 4) + hex_value(p[2]);
- return p + 3;
- }
- error_at(this->location(), "invalid hex character");
- return (Lex::is_hex_digit(p[1])
- ? p + 2
- : p + 1);
-
- case 'a':
- *value = '\a';
- return p + 1;
- case 'b':
- *value = '\b';
- return p + 1;
- case 'f':
- *value = '\f';
- return p + 1;
- case 'n':
- *value = '\n';
- return p + 1;
- case 'r':
- *value = '\r';
- return p + 1;
- case 't':
- *value = '\t';
- return p + 1;
- case 'v':
- *value = '\v';
- return p + 1;
- case '\\':
- *value = '\\';
- return p + 1;
- case '\'':
- if (!is_single_quote)
- error_at(this->location(), "invalid quoted character");
- *value = '\'';
- return p + 1;
- case '"':
- if (is_single_quote)
- error_at(this->location(), "invalid quoted character");
- *value = '"';
- return p + 1;
-
- case 'u':
- if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2])
- && Lex::is_hex_digit(p[3]) && Lex::is_hex_digit(p[4]))
- {
- *value = ((hex_value(p[1]) << 12)
- + (hex_value(p[2]) << 8)
- + (hex_value(p[3]) << 4)
- + hex_value(p[4]));
- if (*value >= 0xd800 && *value < 0xe000)
- {
- error_at(this->location(),
- "invalid unicode code point 0x%x",
- *value);
- // Use the replacement character.
- *value = 0xfffd;
- }
- return p + 5;
- }
- error_at(this->location(), "invalid little unicode code point");
- return p + 1;
-
- case 'U':
- if (Lex::is_hex_digit(p[1]) && Lex::is_hex_digit(p[2])
- && Lex::is_hex_digit(p[3]) && Lex::is_hex_digit(p[4])
- && Lex::is_hex_digit(p[5]) && Lex::is_hex_digit(p[6])
- && Lex::is_hex_digit(p[7]) && Lex::is_hex_digit(p[8]))
- {
- *value = ((hex_value(p[1]) << 28)
- + (hex_value(p[2]) << 24)
- + (hex_value(p[3]) << 20)
- + (hex_value(p[4]) << 16)
- + (hex_value(p[5]) << 12)
- + (hex_value(p[6]) << 8)
- + (hex_value(p[7]) << 4)
- + hex_value(p[8]));
- if (*value > 0x10ffff
- || (*value >= 0xd800 && *value < 0xe000))
- {
- error_at(this->location(), "invalid unicode code point 0x%x",
- *value);
- // Use the replacement character.
- *value = 0xfffd;
- }
- return p + 9;
- }
- error_at(this->location(), "invalid big unicode code point");
- return p + 1;
-
- default:
- error_at(this->location(), "invalid character after %<\\%>");
- *value = *p;
- return p + 1;
- }
- }
-}
-
-// Append V to STR. IS_CHARACTER is true for a character which should
-// be stored in UTF-8, false for a general byte value which should be
-// stored directly.
-
-void
-Lex::append_char(unsigned int v, bool is_character, std::string* str,
- Location location)
-{
- char buf[4];
- size_t len;
- if (v <= 0x7f || !is_character)
- {
- buf[0] = v;
- len = 1;
- }
- else if (v <= 0x7ff)
- {
- buf[0] = 0xc0 + (v >> 6);
- buf[1] = 0x80 + (v & 0x3f);
- len = 2;
- }
- else
- {
- if (v > 0x10ffff)
- {
- warning_at(location, 0,
- "unicode code point 0x%x out of range in string", v);
- // Turn it into the "replacement character".
- v = 0xfffd;
- }
- if (v >= 0xd800 && v < 0xe000)
- {
- warning_at(location, 0,
- "unicode code point 0x%x is invalid surrogate pair", v);
- v = 0xfffd;
- }
- if (v <= 0xffff)
- {
- buf[0] = 0xe0 + (v >> 12);
- buf[1] = 0x80 + ((v >> 6) & 0x3f);
- buf[2] = 0x80 + (v & 0x3f);
- len = 3;
- }
- else
- {
- buf[0] = 0xf0 + (v >> 18);
- buf[1] = 0x80 + ((v >> 12) & 0x3f);
- buf[2] = 0x80 + ((v >> 6) & 0x3f);
- buf[3] = 0x80 + (v & 0x3f);
- len = 4;
- }
- }
- str->append(buf, len);
-}
-
-// Pick up a character literal.
-
-Token
-Lex::gather_character()
-{
- ++this->lineoff_;
- const char* pstart = this->linebuf_ + this->lineoff_;
- const char* p = pstart;
-
- unsigned int value;
- bool is_character;
- p = this->advance_one_char(p, true, &value, &is_character);
-
- if (*p != '\'')
- {
- error_at(this->location(), "unterminated character constant");
- this->lineoff_ = p - this->linebuf_;
- return this->make_invalid_token();
- }
-
- mpz_t val;
- mpz_init_set_ui(val, value);
-
- Location location = this->location();
- this->lineoff_ = p + 1 - this->linebuf_;
- Token ret = Token::make_character_token(val, location);
- mpz_clear(val);
- return ret;
-}
-
-// Pick up a quoted string.
-
-Token
-Lex::gather_string()
-{
- const char* pstart = this->linebuf_ + this->lineoff_ + 1;
- const char* p = pstart;
- const char* pend = this->linebuf_ + this->linesize_;
-
- std::string value;
- while (*p != '"')
- {
- Location loc = this->location();
- unsigned int c;
- bool is_character;
- this->lineoff_ = p - this->linebuf_;
- p = this->advance_one_char(p, false, &c, &is_character);
- if (p >= pend)
- {
- error_at(this->location(), "unterminated string");
- --p;
- break;
- }
- Lex::append_char(c, is_character, &value, loc);
- }
-
- Location location = this->location();
- this->lineoff_ = p + 1 - this->linebuf_;
- return Token::make_string_token(value, location);
-}
-
-// Pick up a raw string.
-
-Token
-Lex::gather_raw_string()
-{
- const char* p = this->linebuf_ + this->lineoff_ + 1;
- const char* pend = this->linebuf_ + this->linesize_;
- Location location = this->location();
-
- std::string value;
- while (true)
- {
- while (p < pend)
- {
- if (*p == '`')
- {
- this->lineoff_ = p + 1 - this->linebuf_;
- return Token::make_string_token(value, location);
- }
- Location loc = this->location();
- unsigned int c;
- bool issued_error;
- this->lineoff_ = p - this->linebuf_;
- p = this->advance_one_utf8_char(p, &c, &issued_error);
- Lex::append_char(c, true, &value, loc);
- }
- this->lineoff_ = p - this->linebuf_;
- if (!this->require_line())
- {
- error_at(location, "unterminated raw string");
- return Token::make_string_token(value, location);
- }
- p = this->linebuf_ + this->lineoff_;
- pend = this->linebuf_ + this->linesize_;
- }
-}
-
-// If C1 C2 C3 are a three character operator, return the code.
-
-Operator
-Lex::three_character_operator(char c1, char c2, char c3)
-{
- if (c3 == '=')
- {
- if (c1 == '<' && c2 == '<')
- return OPERATOR_LSHIFTEQ;
- else if (c1 == '>' && c2 == '>')
- return OPERATOR_RSHIFTEQ;
- else if (c1 == '&' && c2 == '^')
- return OPERATOR_BITCLEAREQ;
- }
- return OPERATOR_INVALID;
-}
-
-// If C1 C2 are a two character operator, return the code.
-
-Operator
-Lex::two_character_operator(char c1, char c2)
-{
- switch (c1)
- {
- case '|':
- if (c2 == '|')
- return OPERATOR_OROR;
- else if (c2 == '=')
- return OPERATOR_OREQ;
- break;
- case '&':
- if (c2 == '&')
- return OPERATOR_ANDAND;
- else if (c2 == '^')
- return OPERATOR_BITCLEAR;
- else if (c2 == '=')
- return OPERATOR_ANDEQ;
- break;
- case '^':
- if (c2 == '=')
- return OPERATOR_XOREQ;
- break;
- case '=':
- if (c2 == '=')
- return OPERATOR_EQEQ;
- break;
- case '!':
- if (c2 == '=')
- return OPERATOR_NOTEQ;
- break;
- case '<':
- if (c2 == '=')
- return OPERATOR_LE;
- else if (c2 == '<')
- return OPERATOR_LSHIFT;
- else if (c2 == '-')
- return OPERATOR_CHANOP;
- break;
- case '>':
- if (c2 == '=')
- return OPERATOR_GE;
- else if (c2 == '>')
- return OPERATOR_RSHIFT;
- break;
- case '*':
- if (c2 == '=')
- return OPERATOR_MULTEQ;
- break;
- case '/':
- if (c2 == '=')
- return OPERATOR_DIVEQ;
- break;
- case '%':
- if (c2 == '=')
- return OPERATOR_MODEQ;
- break;
- case '+':
- if (c2 == '+')
- {
- this->add_semi_at_eol_ = true;
- return OPERATOR_PLUSPLUS;
- }
- else if (c2 == '=')
- return OPERATOR_PLUSEQ;
- break;
- case '-':
- if (c2 == '-')
- {
- this->add_semi_at_eol_ = true;
- return OPERATOR_MINUSMINUS;
- }
- else if (c2 == '=')
- return OPERATOR_MINUSEQ;
- break;
- case ':':
- if (c2 == '=')
- return OPERATOR_COLONEQ;
- break;
- default:
- break;
- }
- return OPERATOR_INVALID;
-}
-
-// If character C is an operator, return the code.
-
-Operator
-Lex::one_character_operator(char c)
-{
- switch (c)
- {
- case '<':
- return OPERATOR_LT;
- case '>':
- return OPERATOR_GT;
- case '+':
- return OPERATOR_PLUS;
- case '-':
- return OPERATOR_MINUS;
- case '|':
- return OPERATOR_OR;
- case '^':
- return OPERATOR_XOR;
- case '*':
- return OPERATOR_MULT;
- case '/':
- return OPERATOR_DIV;
- case '%':
- return OPERATOR_MOD;
- case '&':
- return OPERATOR_AND;
- case '!':
- return OPERATOR_NOT;
- case '=':
- return OPERATOR_EQ;
- case ':':
- return OPERATOR_COLON;
- case ';':
- return OPERATOR_SEMICOLON;
- case '.':
- return OPERATOR_DOT;
- case ',':
- return OPERATOR_COMMA;
- case '(':
- return OPERATOR_LPAREN;
- case ')':
- this->add_semi_at_eol_ = true;
- return OPERATOR_RPAREN;
- case '{':
- return OPERATOR_LCURLY;
- case '}':
- this->add_semi_at_eol_ = true;
- return OPERATOR_RCURLY;
- case '[':
- return OPERATOR_LSQUARE;
- case ']':
- this->add_semi_at_eol_ = true;
- return OPERATOR_RSQUARE;
- default:
- return OPERATOR_INVALID;
- }
-}
-
-// Skip a C-style comment.
-
-bool
-Lex::skip_c_comment()
-{
- while (true)
- {
- if (!this->require_line())
- {
- error_at(this->location(), "unterminated comment");
- return false;
- }
-
- const char* p = this->linebuf_ + this->lineoff_;
- const char* pend = this->linebuf_ + this->linesize_;
-
- while (p < pend)
- {
- if (p[0] == '*' && p + 1 < pend && p[1] == '/')
- {
- this->lineoff_ = p + 2 - this->linebuf_;
- return true;
- }
-
- this->lineoff_ = p - this->linebuf_;
- unsigned int c;
- bool issued_error;
- p = this->advance_one_utf8_char(p, &c, &issued_error);
- }
-
- this->lineoff_ = p - this->linebuf_;
- }
-}
-
-// Skip a C++-style comment.
-
-void
-Lex::skip_cpp_comment()
-{
- // Ensure that if EXTERN_ is set, it means that we just saw a
- // //extern comment.
- this->extern_.clear();
-
- const char* p = this->linebuf_ + this->lineoff_;
- const char* pend = this->linebuf_ + this->linesize_;
-
- // By convention, a C++ comment at the start of the line of the form
- // //line FILE:LINENO
- // is interpreted as setting the file name and line number of the
- // next source line.
-
- if (this->lineoff_ == 2
- && pend - p > 5
- && memcmp(p, "line ", 5) == 0)
- {
- p += 5;
- while (p < pend && *p == ' ')
- ++p;
- const char* pcolon = static_cast<const char*>(memchr(p, ':', pend - p));
- if (pcolon != NULL
- && pcolon[1] >= '0'
- && pcolon[1] <= '9')
- {
- char* plend;
- long lineno = strtol(pcolon + 1, &plend, 10);
- if (plend > pcolon + 1
- && (plend == pend
- || *plend < '0'
- || *plend > '9')
- && lineno > 0
- && lineno < 0x7fffffff)
- {
- unsigned int filelen = pcolon - p;
- char* file = new char[filelen + 1];
- memcpy(file, p, filelen);
- file[filelen] = '\0';
-
- this->linemap_->start_file(file, lineno);
- this->lineno_ = lineno - 1;
-
- p = plend;
- }
- }
- }
-
- // As a special gccgo extension, a C++ comment at the start of the
- // line of the form
- // //extern NAME
- // which immediately precedes a function declaration means that the
- // external name of the function declaration is NAME. This is
- // normally used to permit Go code to call a C function.
- if (this->lineoff_ == 2
- && pend - p > 7
- && memcmp(p, "extern ", 7) == 0)
- {
- p += 7;
- while (p < pend && (*p == ' ' || *p == '\t'))
- ++p;
- const char* plend = pend;
- while (plend > p
- && (plend[-1] == ' ' || plend[-1] == '\t' || plend[-1] == '\n'))
- --plend;
- if (plend > p)
- this->extern_ = std::string(p, plend - p);
- }
-
- // For field tracking analysis: a //go:nointerface comment means
- // that the next interface method should not be stored in the type
- // descriptor. This permits it to be discarded if it is not needed.
- if (this->lineoff_ == 2 && memcmp(p, "go:nointerface", 14) == 0)
- this->saw_nointerface_ = true;
-
- while (p < pend)
- {
- this->lineoff_ = p - this->linebuf_;
- unsigned int c;
- bool issued_error;
- p = this->advance_one_utf8_char(p, &c, &issued_error);
- if (issued_error)
- this->extern_.clear();
- }
-}
-
-// The Unicode tables use this struct.
-
-struct Unicode_range
-{
- // The low end of the range.
- unsigned int low;
- // The high end of the range.
- unsigned int high;
- // The stride. This entries represents low, low + stride, low + 2 *
- // stride, etc., up to high.
- unsigned int stride;
-};
-
-// A table of whitespace characters--Unicode code points classified as
-// "Space", "C" locale whitespace characters, the "next line" control
-// character (0085), the line separator (2028), the paragraph
-// separator (2029), and the "zero-width non-break space" (feff).
-
-static const Unicode_range unicode_space[] =
-{
- { 0x0009, 0x000d, 1 },
- { 0x0020, 0x0020, 1 },
- { 0x0085, 0x0085, 1 },
- { 0x00a0, 0x00a0, 1 },
- { 0x1680, 0x1680, 1 },
- { 0x180e, 0x180e, 1 },
- { 0x2000, 0x200a, 1 },
- { 0x2028, 0x2029, 1 },
- { 0x202f, 0x202f, 1 },
- { 0x205f, 0x205f, 1 },
- { 0x3000, 0x3000, 1 },
- { 0xfeff, 0xfeff, 1 },
-};
-
-// A table of Unicode digits--Unicode code points classified as
-// "Digit".
-
-static const Unicode_range unicode_digits[] =
-{
- { 0x0030, 0x0039, 1},
- { 0x0660, 0x0669, 1},
- { 0x06f0, 0x06f9, 1},
- { 0x07c0, 0x07c9, 1},
- { 0x0966, 0x096f, 1},
- { 0x09e6, 0x09ef, 1},
- { 0x0a66, 0x0a6f, 1},
- { 0x0ae6, 0x0aef, 1},
- { 0x0b66, 0x0b6f, 1},
- { 0x0be6, 0x0bef, 1},
- { 0x0c66, 0x0c6f, 1},
- { 0x0ce6, 0x0cef, 1},
- { 0x0d66, 0x0d6f, 1},
- { 0x0e50, 0x0e59, 1},
- { 0x0ed0, 0x0ed9, 1},
- { 0x0f20, 0x0f29, 1},
- { 0x1040, 0x1049, 1},
- { 0x17e0, 0x17e9, 1},
- { 0x1810, 0x1819, 1},
- { 0x1946, 0x194f, 1},
- { 0x19d0, 0x19d9, 1},
- { 0x1b50, 0x1b59, 1},
- { 0xff10, 0xff19, 1},
- { 0x104a0, 0x104a9, 1},
- { 0x1d7ce, 0x1d7ff, 1},
-};
-
-// A table of Unicode letters--Unicode code points classified as
-// "Letter".
-
-static const Unicode_range unicode_letters[] =
-{
- { 0x0041, 0x005a, 1},
- { 0x0061, 0x007a, 1},
- { 0x00aa, 0x00b5, 11},
- { 0x00ba, 0x00ba, 1},
- { 0x00c0, 0x00d6, 1},
- { 0x00d8, 0x00f6, 1},
- { 0x00f8, 0x02c1, 1},
- { 0x02c6, 0x02d1, 1},
- { 0x02e0, 0x02e4, 1},
- { 0x02ec, 0x02ee, 2},
- { 0x0370, 0x0374, 1},
- { 0x0376, 0x0377, 1},
- { 0x037a, 0x037d, 1},
- { 0x0386, 0x0386, 1},
- { 0x0388, 0x038a, 1},
- { 0x038c, 0x038c, 1},
- { 0x038e, 0x03a1, 1},
- { 0x03a3, 0x03f5, 1},
- { 0x03f7, 0x0481, 1},
- { 0x048a, 0x0523, 1},
- { 0x0531, 0x0556, 1},
- { 0x0559, 0x0559, 1},
- { 0x0561, 0x0587, 1},
- { 0x05d0, 0x05ea, 1},
- { 0x05f0, 0x05f2, 1},
- { 0x0621, 0x064a, 1},
- { 0x066e, 0x066f, 1},
- { 0x0671, 0x06d3, 1},
- { 0x06d5, 0x06d5, 1},
- { 0x06e5, 0x06e6, 1},
- { 0x06ee, 0x06ef, 1},
- { 0x06fa, 0x06fc, 1},
- { 0x06ff, 0x0710, 17},
- { 0x0712, 0x072f, 1},
- { 0x074d, 0x07a5, 1},
- { 0x07b1, 0x07b1, 1},
- { 0x07ca, 0x07ea, 1},
- { 0x07f4, 0x07f5, 1},
- { 0x07fa, 0x07fa, 1},
- { 0x0904, 0x0939, 1},
- { 0x093d, 0x0950, 19},
- { 0x0958, 0x0961, 1},
- { 0x0971, 0x0972, 1},
- { 0x097b, 0x097f, 1},
- { 0x0985, 0x098c, 1},
- { 0x098f, 0x0990, 1},
- { 0x0993, 0x09a8, 1},
- { 0x09aa, 0x09b0, 1},
- { 0x09b2, 0x09b2, 1},
- { 0x09b6, 0x09b9, 1},
- { 0x09bd, 0x09ce, 17},
- { 0x09dc, 0x09dd, 1},
- { 0x09df, 0x09e1, 1},
- { 0x09f0, 0x09f1, 1},
- { 0x0a05, 0x0a0a, 1},
- { 0x0a0f, 0x0a10, 1},
- { 0x0a13, 0x0a28, 1},
- { 0x0a2a, 0x0a30, 1},
- { 0x0a32, 0x0a33, 1},
- { 0x0a35, 0x0a36, 1},
- { 0x0a38, 0x0a39, 1},
- { 0x0a59, 0x0a5c, 1},
- { 0x0a5e, 0x0a5e, 1},
- { 0x0a72, 0x0a74, 1},
- { 0x0a85, 0x0a8d, 1},
- { 0x0a8f, 0x0a91, 1},
- { 0x0a93, 0x0aa8, 1},
- { 0x0aaa, 0x0ab0, 1},
- { 0x0ab2, 0x0ab3, 1},
- { 0x0ab5, 0x0ab9, 1},
- { 0x0abd, 0x0ad0, 19},
- { 0x0ae0, 0x0ae1, 1},
- { 0x0b05, 0x0b0c, 1},
- { 0x0b0f, 0x0b10, 1},
- { 0x0b13, 0x0b28, 1},
- { 0x0b2a, 0x0b30, 1},
- { 0x0b32, 0x0b33, 1},
- { 0x0b35, 0x0b39, 1},
- { 0x0b3d, 0x0b3d, 1},
- { 0x0b5c, 0x0b5d, 1},
- { 0x0b5f, 0x0b61, 1},
- { 0x0b71, 0x0b83, 18},
- { 0x0b85, 0x0b8a, 1},
- { 0x0b8e, 0x0b90, 1},
- { 0x0b92, 0x0b95, 1},
- { 0x0b99, 0x0b9a, 1},
- { 0x0b9c, 0x0b9c, 1},
- { 0x0b9e, 0x0b9f, 1},
- { 0x0ba3, 0x0ba4, 1},
- { 0x0ba8, 0x0baa, 1},
- { 0x0bae, 0x0bb9, 1},
- { 0x0bd0, 0x0bd0, 1},
- { 0x0c05, 0x0c0c, 1},
- { 0x0c0e, 0x0c10, 1},
- { 0x0c12, 0x0c28, 1},
- { 0x0c2a, 0x0c33, 1},
- { 0x0c35, 0x0c39, 1},
- { 0x0c3d, 0x0c3d, 1},
- { 0x0c58, 0x0c59, 1},
- { 0x0c60, 0x0c61, 1},
- { 0x0c85, 0x0c8c, 1},
- { 0x0c8e, 0x0c90, 1},
- { 0x0c92, 0x0ca8, 1},
- { 0x0caa, 0x0cb3, 1},
- { 0x0cb5, 0x0cb9, 1},
- { 0x0cbd, 0x0cde, 33},
- { 0x0ce0, 0x0ce1, 1},
- { 0x0d05, 0x0d0c, 1},
- { 0x0d0e, 0x0d10, 1},
- { 0x0d12, 0x0d28, 1},
- { 0x0d2a, 0x0d39, 1},
- { 0x0d3d, 0x0d3d, 1},
- { 0x0d60, 0x0d61, 1},
- { 0x0d7a, 0x0d7f, 1},
- { 0x0d85, 0x0d96, 1},
- { 0x0d9a, 0x0db1, 1},
- { 0x0db3, 0x0dbb, 1},
- { 0x0dbd, 0x0dbd, 1},
- { 0x0dc0, 0x0dc6, 1},
- { 0x0e01, 0x0e30, 1},
- { 0x0e32, 0x0e33, 1},
- { 0x0e40, 0x0e46, 1},
- { 0x0e81, 0x0e82, 1},
- { 0x0e84, 0x0e84, 1},
- { 0x0e87, 0x0e88, 1},
- { 0x0e8a, 0x0e8d, 3},
- { 0x0e94, 0x0e97, 1},
- { 0x0e99, 0x0e9f, 1},
- { 0x0ea1, 0x0ea3, 1},
- { 0x0ea5, 0x0ea7, 2},
- { 0x0eaa, 0x0eab, 1},
- { 0x0ead, 0x0eb0, 1},
- { 0x0eb2, 0x0eb3, 1},
- { 0x0ebd, 0x0ebd, 1},
- { 0x0ec0, 0x0ec4, 1},
- { 0x0ec6, 0x0ec6, 1},
- { 0x0edc, 0x0edd, 1},
- { 0x0f00, 0x0f00, 1},
- { 0x0f40, 0x0f47, 1},
- { 0x0f49, 0x0f6c, 1},
- { 0x0f88, 0x0f8b, 1},
- { 0x1000, 0x102a, 1},
- { 0x103f, 0x103f, 1},
- { 0x1050, 0x1055, 1},
- { 0x105a, 0x105d, 1},
- { 0x1061, 0x1061, 1},
- { 0x1065, 0x1066, 1},
- { 0x106e, 0x1070, 1},
- { 0x1075, 0x1081, 1},
- { 0x108e, 0x108e, 1},
- { 0x10a0, 0x10c5, 1},
- { 0x10d0, 0x10fa, 1},
- { 0x10fc, 0x10fc, 1},
- { 0x1100, 0x1159, 1},
- { 0x115f, 0x11a2, 1},
- { 0x11a8, 0x11f9, 1},
- { 0x1200, 0x1248, 1},
- { 0x124a, 0x124d, 1},
- { 0x1250, 0x1256, 1},
- { 0x1258, 0x1258, 1},
- { 0x125a, 0x125d, 1},
- { 0x1260, 0x1288, 1},
- { 0x128a, 0x128d, 1},
- { 0x1290, 0x12b0, 1},
- { 0x12b2, 0x12b5, 1},
- { 0x12b8, 0x12be, 1},
- { 0x12c0, 0x12c0, 1},
- { 0x12c2, 0x12c5, 1},
- { 0x12c8, 0x12d6, 1},
- { 0x12d8, 0x1310, 1},
- { 0x1312, 0x1315, 1},
- { 0x1318, 0x135a, 1},
- { 0x1380, 0x138f, 1},
- { 0x13a0, 0x13f4, 1},
- { 0x1401, 0x166c, 1},
- { 0x166f, 0x1676, 1},
- { 0x1681, 0x169a, 1},
- { 0x16a0, 0x16ea, 1},
- { 0x1700, 0x170c, 1},
- { 0x170e, 0x1711, 1},
- { 0x1720, 0x1731, 1},
- { 0x1740, 0x1751, 1},
- { 0x1760, 0x176c, 1},
- { 0x176e, 0x1770, 1},
- { 0x1780, 0x17b3, 1},
- { 0x17d7, 0x17dc, 5},
- { 0x1820, 0x1877, 1},
- { 0x1880, 0x18a8, 1},
- { 0x18aa, 0x18aa, 1},
- { 0x1900, 0x191c, 1},
- { 0x1950, 0x196d, 1},
- { 0x1970, 0x1974, 1},
- { 0x1980, 0x19a9, 1},
- { 0x19c1, 0x19c7, 1},
- { 0x1a00, 0x1a16, 1},
- { 0x1b05, 0x1b33, 1},
- { 0x1b45, 0x1b4b, 1},
- { 0x1b83, 0x1ba0, 1},
- { 0x1bae, 0x1baf, 1},
- { 0x1c00, 0x1c23, 1},
- { 0x1c4d, 0x1c4f, 1},
- { 0x1c5a, 0x1c7d, 1},
- { 0x1d00, 0x1dbf, 1},
- { 0x1e00, 0x1f15, 1},
- { 0x1f18, 0x1f1d, 1},
- { 0x1f20, 0x1f45, 1},
- { 0x1f48, 0x1f4d, 1},
- { 0x1f50, 0x1f57, 1},
- { 0x1f59, 0x1f5d, 2},
- { 0x1f5f, 0x1f7d, 1},
- { 0x1f80, 0x1fb4, 1},
- { 0x1fb6, 0x1fbc, 1},
- { 0x1fbe, 0x1fbe, 1},
- { 0x1fc2, 0x1fc4, 1},
- { 0x1fc6, 0x1fcc, 1},
- { 0x1fd0, 0x1fd3, 1},
- { 0x1fd6, 0x1fdb, 1},
- { 0x1fe0, 0x1fec, 1},
- { 0x1ff2, 0x1ff4, 1},
- { 0x1ff6, 0x1ffc, 1},
- { 0x2071, 0x207f, 14},
- { 0x2090, 0x2094, 1},
- { 0x2102, 0x2107, 5},
- { 0x210a, 0x2113, 1},
- { 0x2115, 0x2115, 1},
- { 0x2119, 0x211d, 1},
- { 0x2124, 0x2128, 2},
- { 0x212a, 0x212d, 1},
- { 0x212f, 0x2139, 1},
- { 0x213c, 0x213f, 1},
- { 0x2145, 0x2149, 1},
- { 0x214e, 0x214e, 1},
- { 0x2183, 0x2184, 1},
- { 0x2c00, 0x2c2e, 1},
- { 0x2c30, 0x2c5e, 1},
- { 0x2c60, 0x2c6f, 1},
- { 0x2c71, 0x2c7d, 1},
- { 0x2c80, 0x2ce4, 1},
- { 0x2d00, 0x2d25, 1},
- { 0x2d30, 0x2d65, 1},
- { 0x2d6f, 0x2d6f, 1},
- { 0x2d80, 0x2d96, 1},
- { 0x2da0, 0x2da6, 1},
- { 0x2da8, 0x2dae, 1},
- { 0x2db0, 0x2db6, 1},
- { 0x2db8, 0x2dbe, 1},
- { 0x2dc0, 0x2dc6, 1},
- { 0x2dc8, 0x2dce, 1},
- { 0x2dd0, 0x2dd6, 1},
- { 0x2dd8, 0x2dde, 1},
- { 0x2e2f, 0x2e2f, 1},
- { 0x3005, 0x3006, 1},
- { 0x3031, 0x3035, 1},
- { 0x303b, 0x303c, 1},
- { 0x3041, 0x3096, 1},
- { 0x309d, 0x309f, 1},
- { 0x30a1, 0x30fa, 1},
- { 0x30fc, 0x30ff, 1},
- { 0x3105, 0x312d, 1},
- { 0x3131, 0x318e, 1},
- { 0x31a0, 0x31b7, 1},
- { 0x31f0, 0x31ff, 1},
- { 0x3400, 0x4db5, 1},
- { 0x4e00, 0x9fc3, 1},
- { 0xa000, 0xa48c, 1},
- { 0xa500, 0xa60c, 1},
- { 0xa610, 0xa61f, 1},
- { 0xa62a, 0xa62b, 1},
- { 0xa640, 0xa65f, 1},
- { 0xa662, 0xa66e, 1},
- { 0xa67f, 0xa697, 1},
- { 0xa717, 0xa71f, 1},
- { 0xa722, 0xa788, 1},
- { 0xa78b, 0xa78c, 1},
- { 0xa7fb, 0xa801, 1},
- { 0xa803, 0xa805, 1},
- { 0xa807, 0xa80a, 1},
- { 0xa80c, 0xa822, 1},
- { 0xa840, 0xa873, 1},
- { 0xa882, 0xa8b3, 1},
- { 0xa90a, 0xa925, 1},
- { 0xa930, 0xa946, 1},
- { 0xaa00, 0xaa28, 1},
- { 0xaa40, 0xaa42, 1},
- { 0xaa44, 0xaa4b, 1},
- { 0xac00, 0xd7a3, 1},
- { 0xf900, 0xfa2d, 1},
- { 0xfa30, 0xfa6a, 1},
- { 0xfa70, 0xfad9, 1},
- { 0xfb00, 0xfb06, 1},
- { 0xfb13, 0xfb17, 1},
- { 0xfb1d, 0xfb1d, 1},
- { 0xfb1f, 0xfb28, 1},
- { 0xfb2a, 0xfb36, 1},
- { 0xfb38, 0xfb3c, 1},
- { 0xfb3e, 0xfb3e, 1},
- { 0xfb40, 0xfb41, 1},
- { 0xfb43, 0xfb44, 1},
- { 0xfb46, 0xfbb1, 1},
- { 0xfbd3, 0xfd3d, 1},
- { 0xfd50, 0xfd8f, 1},
- { 0xfd92, 0xfdc7, 1},
- { 0xfdf0, 0xfdfb, 1},
- { 0xfe70, 0xfe74, 1},
- { 0xfe76, 0xfefc, 1},
- { 0xff21, 0xff3a, 1},
- { 0xff41, 0xff5a, 1},
- { 0xff66, 0xffbe, 1},
- { 0xffc2, 0xffc7, 1},
- { 0xffca, 0xffcf, 1},
- { 0xffd2, 0xffd7, 1},
- { 0xffda, 0xffdc, 1},
- { 0x10000, 0x1000b, 1},
- { 0x1000d, 0x10026, 1},
- { 0x10028, 0x1003a, 1},
- { 0x1003c, 0x1003d, 1},
- { 0x1003f, 0x1004d, 1},
- { 0x10050, 0x1005d, 1},
- { 0x10080, 0x100fa, 1},
- { 0x10280, 0x1029c, 1},
- { 0x102a0, 0x102d0, 1},
- { 0x10300, 0x1031e, 1},
- { 0x10330, 0x10340, 1},
- { 0x10342, 0x10349, 1},
- { 0x10380, 0x1039d, 1},
- { 0x103a0, 0x103c3, 1},
- { 0x103c8, 0x103cf, 1},
- { 0x10400, 0x1049d, 1},
- { 0x10800, 0x10805, 1},
- { 0x10808, 0x10808, 1},
- { 0x1080a, 0x10835, 1},
- { 0x10837, 0x10838, 1},
- { 0x1083c, 0x1083f, 3},
- { 0x10900, 0x10915, 1},
- { 0x10920, 0x10939, 1},
- { 0x10a00, 0x10a00, 1},
- { 0x10a10, 0x10a13, 1},
- { 0x10a15, 0x10a17, 1},
- { 0x10a19, 0x10a33, 1},
- { 0x12000, 0x1236e, 1},
- { 0x1d400, 0x1d454, 1},
- { 0x1d456, 0x1d49c, 1},
- { 0x1d49e, 0x1d49f, 1},
- { 0x1d4a2, 0x1d4a2, 1},
- { 0x1d4a5, 0x1d4a6, 1},
- { 0x1d4a9, 0x1d4ac, 1},
- { 0x1d4ae, 0x1d4b9, 1},
- { 0x1d4bb, 0x1d4bb, 1},
- { 0x1d4bd, 0x1d4c3, 1},
- { 0x1d4c5, 0x1d505, 1},
- { 0x1d507, 0x1d50a, 1},
- { 0x1d50d, 0x1d514, 1},
- { 0x1d516, 0x1d51c, 1},
- { 0x1d51e, 0x1d539, 1},
- { 0x1d53b, 0x1d53e, 1},
- { 0x1d540, 0x1d544, 1},
- { 0x1d546, 0x1d546, 1},
- { 0x1d54a, 0x1d550, 1},
- { 0x1d552, 0x1d6a5, 1},
- { 0x1d6a8, 0x1d6c0, 1},
- { 0x1d6c2, 0x1d6da, 1},
- { 0x1d6dc, 0x1d6fa, 1},
- { 0x1d6fc, 0x1d714, 1},
- { 0x1d716, 0x1d734, 1},
- { 0x1d736, 0x1d74e, 1},
- { 0x1d750, 0x1d76e, 1},
- { 0x1d770, 0x1d788, 1},
- { 0x1d78a, 0x1d7a8, 1},
- { 0x1d7aa, 0x1d7c2, 1},
- { 0x1d7c4, 0x1d7cb, 1},
- { 0x20000, 0x2a6d6, 1},
- { 0x2f800, 0x2fa1d, 1},
-};
-
-// A table of Unicode uppercase letters--Unicode code points
-// classified as "Letter, uppercase".
-
-static const Unicode_range unicode_uppercase_letters[] =
-{
- { 0x0041, 0x005a, 1},
- { 0x00c0, 0x00d6, 1},
- { 0x00d8, 0x00de, 1},
- { 0x0100, 0x0136, 2},
- { 0x0139, 0x0147, 2},
- { 0x014a, 0x0176, 2},
- { 0x0178, 0x0179, 1},
- { 0x017b, 0x017d, 2},
- { 0x0181, 0x0182, 1},
- { 0x0184, 0x0184, 1},
- { 0x0186, 0x0187, 1},
- { 0x0189, 0x018b, 1},
- { 0x018e, 0x0191, 1},
- { 0x0193, 0x0194, 1},
- { 0x0196, 0x0198, 1},
- { 0x019c, 0x019d, 1},
- { 0x019f, 0x01a0, 1},
- { 0x01a2, 0x01a4, 2},
- { 0x01a6, 0x01a7, 1},
- { 0x01a9, 0x01ac, 3},
- { 0x01ae, 0x01af, 1},
- { 0x01b1, 0x01b3, 1},
- { 0x01b5, 0x01b5, 1},
- { 0x01b7, 0x01b8, 1},
- { 0x01bc, 0x01c4, 8},
- { 0x01c7, 0x01cd, 3},
- { 0x01cf, 0x01db, 2},
- { 0x01de, 0x01ee, 2},
- { 0x01f1, 0x01f4, 3},
- { 0x01f6, 0x01f8, 1},
- { 0x01fa, 0x0232, 2},
- { 0x023a, 0x023b, 1},
- { 0x023d, 0x023e, 1},
- { 0x0241, 0x0241, 1},
- { 0x0243, 0x0246, 1},
- { 0x0248, 0x024e, 2},
- { 0x0370, 0x0372, 2},
- { 0x0376, 0x0386, 16},
- { 0x0388, 0x038a, 1},
- { 0x038c, 0x038c, 1},
- { 0x038e, 0x038f, 1},
- { 0x0391, 0x03a1, 1},
- { 0x03a3, 0x03ab, 1},
- { 0x03cf, 0x03cf, 1},
- { 0x03d2, 0x03d4, 1},
- { 0x03d8, 0x03ee, 2},
- { 0x03f4, 0x03f7, 3},
- { 0x03f9, 0x03fa, 1},
- { 0x03fd, 0x042f, 1},
- { 0x0460, 0x0480, 2},
- { 0x048a, 0x04be, 2},
- { 0x04c0, 0x04c1, 1},
- { 0x04c3, 0x04cd, 2},
- { 0x04d0, 0x0522, 2},
- { 0x0531, 0x0556, 1},
- { 0x10a0, 0x10c5, 1},
- { 0x1e00, 0x1e94, 2},
- { 0x1e9e, 0x1efe, 2},
- { 0x1f08, 0x1f0f, 1},
- { 0x1f18, 0x1f1d, 1},
- { 0x1f28, 0x1f2f, 1},
- { 0x1f38, 0x1f3f, 1},
- { 0x1f48, 0x1f4d, 1},
- { 0x1f59, 0x1f5f, 2},
- { 0x1f68, 0x1f6f, 1},
- { 0x1fb8, 0x1fbb, 1},
- { 0x1fc8, 0x1fcb, 1},
- { 0x1fd8, 0x1fdb, 1},
- { 0x1fe8, 0x1fec, 1},
- { 0x1ff8, 0x1ffb, 1},
- { 0x2102, 0x2107, 5},
- { 0x210b, 0x210d, 1},
- { 0x2110, 0x2112, 1},
- { 0x2115, 0x2115, 1},
- { 0x2119, 0x211d, 1},
- { 0x2124, 0x2128, 2},
- { 0x212a, 0x212d, 1},
- { 0x2130, 0x2133, 1},
- { 0x213e, 0x213f, 1},
- { 0x2145, 0x2183, 62},
- { 0x2c00, 0x2c2e, 1},
- { 0x2c60, 0x2c60, 1},
- { 0x2c62, 0x2c64, 1},
- { 0x2c67, 0x2c6b, 2},
- { 0x2c6d, 0x2c6f, 1},
- { 0x2c72, 0x2c75, 3},
- { 0x2c80, 0x2ce2, 2},
- { 0xa640, 0xa65e, 2},
- { 0xa662, 0xa66c, 2},
- { 0xa680, 0xa696, 2},
- { 0xa722, 0xa72e, 2},
- { 0xa732, 0xa76e, 2},
- { 0xa779, 0xa77b, 2},
- { 0xa77d, 0xa77e, 1},
- { 0xa780, 0xa786, 2},
- { 0xa78b, 0xa78b, 1},
- { 0xff21, 0xff3a, 1},
- { 0x10400, 0x10427, 1},
- { 0x1d400, 0x1d419, 1},
- { 0x1d434, 0x1d44d, 1},
- { 0x1d468, 0x1d481, 1},
- { 0x1d49c, 0x1d49c, 1},
- { 0x1d49e, 0x1d49f, 1},
- { 0x1d4a2, 0x1d4a2, 1},
- { 0x1d4a5, 0x1d4a6, 1},
- { 0x1d4a9, 0x1d4ac, 1},
- { 0x1d4ae, 0x1d4b5, 1},
- { 0x1d4d0, 0x1d4e9, 1},
- { 0x1d504, 0x1d505, 1},
- { 0x1d507, 0x1d50a, 1},
- { 0x1d50d, 0x1d514, 1},
- { 0x1d516, 0x1d51c, 1},
- { 0x1d538, 0x1d539, 1},
- { 0x1d53b, 0x1d53e, 1},
- { 0x1d540, 0x1d544, 1},
- { 0x1d546, 0x1d546, 1},
- { 0x1d54a, 0x1d550, 1},
- { 0x1d56c, 0x1d585, 1},
- { 0x1d5a0, 0x1d5b9, 1},
- { 0x1d5d4, 0x1d5ed, 1},
- { 0x1d608, 0x1d621, 1},
- { 0x1d63c, 0x1d655, 1},
- { 0x1d670, 0x1d689, 1},
- { 0x1d6a8, 0x1d6c0, 1},
- { 0x1d6e2, 0x1d6fa, 1},
- { 0x1d71c, 0x1d734, 1},
- { 0x1d756, 0x1d76e, 1},
- { 0x1d790, 0x1d7a8, 1},
- { 0x1d7ca, 0x1d7ca, 1},
-};
-
-// Return true if C is in RANGES.
-
-bool
-Lex::is_in_unicode_range(unsigned int c, const Unicode_range* ranges,
- size_t range_size)
-{
- if (c < 0x100)
- {
- // The common case is a small value, and we know that it will be
- // in the first few entries of the table. Do a linear scan
- // rather than a binary search.
- for (size_t i = 0; i < range_size; ++i)
- {
- const Unicode_range* p = &ranges[i];
- if (c <= p->high)
- {
- if (c < p->low)
- return false;
- return (c - p->low) % p->stride == 0;
- }
- }
- return false;
- }
- else
- {
- size_t lo = 0;
- size_t hi = range_size;
- while (lo < hi)
- {
- size_t mid = lo + (hi - lo) / 2;
- const Unicode_range* p = &ranges[mid];
- if (c < p->low)
- hi = mid;
- else if (c > p->high)
- lo = mid + 1;
- else
- return (c - p->low) % p->stride == 0;
- }
- return false;
- }
-}
-
-// Return whether C is a space character.
-
-bool
-Lex::is_unicode_space(unsigned int c)
-{
- return Lex::is_in_unicode_range(c, unicode_space,
- ARRAY_SIZE(unicode_space));
-}
-
-// Return whether C is a Unicode digit--a Unicode code point
-// classified as "Digit".
-
-bool
-Lex::is_unicode_digit(unsigned int c)
-{
- return Lex::is_in_unicode_range(c, unicode_digits,
- ARRAY_SIZE(unicode_digits));
-}
-
-// Return whether C is a Unicode letter--a Unicode code point
-// classified as "Letter".
-
-bool
-Lex::is_unicode_letter(unsigned int c)
-{
- return Lex::is_in_unicode_range(c, unicode_letters,
- ARRAY_SIZE(unicode_letters));
-}
-
-// Return whether C is a Unicode uppercase letter. a Unicode code
-// point classified as "Letter, uppercase".
-
-bool
-Lex::is_unicode_uppercase(unsigned int c)
-{
- return Lex::is_in_unicode_range(c, unicode_uppercase_letters,
- ARRAY_SIZE(unicode_uppercase_letters));
-}
-
-// Return whether the identifier NAME should be exported. NAME is a
-// mangled name which includes only ASCII characters.
-
-bool
-Lex::is_exported_name(const std::string& name)
-{
- unsigned char c = name[0];
- if (c != '$')
- return c >= 'A' && c <= 'Z';
- else
- {
- const char* p = name.data();
- size_t len = name.length();
- if (len < 2 || p[1] != 'U')
- return false;
- unsigned int ci = 0;
- for (size_t i = 2; i < len && p[i] != '$'; ++i)
- {
- c = p[i];
- if (!hex_p(c))
- return false;
- ci <<= 4;
- ci |= hex_value(c);
- }
- return Lex::is_unicode_uppercase(ci);
- }
-}
-
-// Return whether the identifier NAME contains an invalid character.
-// This is based on how we handle invalid characters in
-// gather_identifier.
-
-bool
-Lex::is_invalid_identifier(const std::string& name)
-{
- return name.find("$INVALID$") != std::string::npos;
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/lex.h b/gcc-4.8.1/gcc/go/gofrontend/lex.h
deleted file mode 100644
index 383a91787..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/lex.h
+++ /dev/null
@@ -1,502 +0,0 @@
-// lex.h -- Go frontend lexer. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_LEX_H
-#define GO_LEX_H
-
-#include <mpfr.h>
-
-#include "operator.h"
-#include "go-linemap.h"
-
-struct Unicode_range;
-
-// The keywords. These must be in sorted order, other than
-// KEYWORD_INVALID. They must match the Keywords::mapping_ array in
-// lex.cc.
-
-enum Keyword
-{
- KEYWORD_INVALID, // Not a keyword.
- KEYWORD_ASM,
- KEYWORD_BREAK,
- KEYWORD_CASE,
- KEYWORD_CHAN,
- KEYWORD_CONST,
- KEYWORD_CONTINUE,
- KEYWORD_DEFAULT,
- KEYWORD_DEFER,
- KEYWORD_ELSE,
- KEYWORD_FALLTHROUGH,
- KEYWORD_FOR,
- KEYWORD_FUNC,
- KEYWORD_GO,
- KEYWORD_GOTO,
- KEYWORD_IF,
- KEYWORD_IMPORT,
- KEYWORD_INTERFACE,
- KEYWORD_MAP,
- KEYWORD_PACKAGE,
- KEYWORD_RANGE,
- KEYWORD_RETURN,
- KEYWORD_SELECT,
- KEYWORD_STRUCT,
- KEYWORD_SWITCH,
- KEYWORD_TYPE,
- KEYWORD_VAR
-};
-
-// A token returned from the lexer.
-
-class Token
-{
- public:
- // Token classification.
- enum Classification
- {
- // Token is invalid.
- TOKEN_INVALID,
- // Token indicates end of input.
- TOKEN_EOF,
- // Token is a keyword.
- TOKEN_KEYWORD,
- // Token is an identifier.
- TOKEN_IDENTIFIER,
- // Token is a string of characters.
- TOKEN_STRING,
- // Token is an operator.
- TOKEN_OPERATOR,
- // Token is a character constant.
- TOKEN_CHARACTER,
- // Token is an integer.
- TOKEN_INTEGER,
- // Token is a floating point number.
- TOKEN_FLOAT,
- // Token is an imaginary number.
- TOKEN_IMAGINARY
- };
-
- ~Token();
- Token(const Token&);
- Token& operator=(const Token&);
-
- // Get token classification.
- Classification
- classification() const
- { return this->classification_; }
-
- // Make a token for an invalid value.
- static Token
- make_invalid_token(Location location)
- { return Token(TOKEN_INVALID, location); }
-
- // Make a token representing end of file.
- static Token
- make_eof_token(Location location)
- { return Token(TOKEN_EOF, location); }
-
- // Make a keyword token.
- static Token
- make_keyword_token(Keyword keyword, Location location)
- {
- Token tok(TOKEN_KEYWORD, location);
- tok.u_.keyword = keyword;
- return tok;
- }
-
- // Make an identifier token.
- static Token
- make_identifier_token(const std::string& value, bool is_exported,
- Location location)
- {
- Token tok(TOKEN_IDENTIFIER, location);
- tok.u_.identifier_value.name = new std::string(value);
- tok.u_.identifier_value.is_exported = is_exported;
- return tok;
- }
-
- // Make a quoted string token.
- static Token
- make_string_token(const std::string& value, Location location)
- {
- Token tok(TOKEN_STRING, location);
- tok.u_.string_value = new std::string(value);
- return tok;
- }
-
- // Make an operator token.
- static Token
- make_operator_token(Operator op, Location location)
- {
- Token tok(TOKEN_OPERATOR, location);
- tok.u_.op = op;
- return tok;
- }
-
- // Make a character constant token.
- static Token
- make_character_token(mpz_t val, Location location)
- {
- Token tok(TOKEN_CHARACTER, location);
- mpz_init(tok.u_.integer_value);
- mpz_swap(tok.u_.integer_value, val);
- return tok;
- }
-
- // Make an integer token.
- static Token
- make_integer_token(mpz_t val, Location location)
- {
- Token tok(TOKEN_INTEGER, location);
- mpz_init(tok.u_.integer_value);
- mpz_swap(tok.u_.integer_value, val);
- return tok;
- }
-
- // Make a float token.
- static Token
- make_float_token(mpfr_t val, Location location)
- {
- Token tok(TOKEN_FLOAT, location);
- mpfr_init(tok.u_.float_value);
- mpfr_swap(tok.u_.float_value, val);
- return tok;
- }
-
- // Make a token for an imaginary number.
- static Token
- make_imaginary_token(mpfr_t val, Location location)
- {
- Token tok(TOKEN_IMAGINARY, location);
- mpfr_init(tok.u_.float_value);
- mpfr_swap(tok.u_.float_value, val);
- return tok;
- }
-
- // Get the location of the token.
- Location
- location() const
- { return this->location_; }
-
- // Return whether this is an invalid token.
- bool
- is_invalid() const
- { return this->classification_ == TOKEN_INVALID; }
-
- // Return whether this is the EOF token.
- bool
- is_eof() const
- { return this->classification_ == TOKEN_EOF; }
-
- // Return the keyword value for a keyword token.
- Keyword
- keyword() const
- {
- go_assert(this->classification_ == TOKEN_KEYWORD);
- return this->u_.keyword;
- }
-
- // Return whether this is an identifier.
- bool
- is_identifier() const
- { return this->classification_ == TOKEN_IDENTIFIER; }
-
- // Return the identifier.
- const std::string&
- identifier() const
- {
- go_assert(this->classification_ == TOKEN_IDENTIFIER);
- return *this->u_.identifier_value.name;
- }
-
- // Return whether the identifier is exported.
- bool
- is_identifier_exported() const
- {
- go_assert(this->classification_ == TOKEN_IDENTIFIER);
- return this->u_.identifier_value.is_exported;
- }
-
- // Return whether this is a string.
- bool
- is_string() const
- {
- return this->classification_ == TOKEN_STRING;
- }
-
- // Return the value of a string. The returned value is a string of
- // UTF-8 characters.
- std::string
- string_value() const
- {
- go_assert(this->classification_ == TOKEN_STRING);
- return *this->u_.string_value;
- }
-
- // Return the value of a character constant.
- const mpz_t*
- character_value() const
- {
- go_assert(this->classification_ == TOKEN_CHARACTER);
- return &this->u_.integer_value;
- }
-
- // Return the value of an integer.
- const mpz_t*
- integer_value() const
- {
- go_assert(this->classification_ == TOKEN_INTEGER);
- return &this->u_.integer_value;
- }
-
- // Return the value of a float.
- const mpfr_t*
- float_value() const
- {
- go_assert(this->classification_ == TOKEN_FLOAT);
- return &this->u_.float_value;
- }
-
- // Return the value of an imaginary number.
- const mpfr_t*
- imaginary_value() const
- {
- go_assert(this->classification_ == TOKEN_IMAGINARY);
- return &this->u_.float_value;
- }
-
- // Return the operator value for an operator token.
- Operator
- op() const
- {
- go_assert(this->classification_ == TOKEN_OPERATOR);
- return this->u_.op;
- }
-
- // Return whether this token is KEYWORD.
- bool
- is_keyword(Keyword keyword) const
- {
- return (this->classification_ == TOKEN_KEYWORD
- && this->u_.keyword == keyword);
- }
-
- // Return whether this token is OP.
- bool
- is_op(Operator op) const
- { return this->classification_ == TOKEN_OPERATOR && this->u_.op == op; }
-
- // Print the token for debugging.
- void
- print(FILE*) const;
-
- private:
- // Private constructor used by make_..._token functions above.
- Token(Classification, Location);
-
- // Clear the token.
- void
- clear();
-
- // The token classification.
- Classification classification_;
- union
- {
- // The keyword value for TOKEN_KEYWORD.
- Keyword keyword;
- // The token value for TOKEN_IDENTIFIER.
- struct
- {
- // The name of the identifier. This has been mangled to only
- // include ASCII characters.
- std::string* name;
- // Whether this name should be exported. This is true if the
- // first letter in the name is upper case.
- bool is_exported;
- } identifier_value;
- // The string value for TOKEN_STRING.
- std::string* string_value;
- // The token value for TOKEN_CHARACTER or TOKEN_INTEGER.
- mpz_t integer_value;
- // The token value for TOKEN_FLOAT or TOKEN_IMAGINARY.
- mpfr_t float_value;
- // The token value for TOKEN_OPERATOR or the keyword value
- Operator op;
- } u_;
- // The source location.
- Location location_;
-};
-
-// The lexer itself.
-
-class Lex
-{
- public:
- Lex(const char* input_file_name, FILE* input_file, Linemap *linemap);
-
- ~Lex();
-
- // Return the next token.
- Token
- next_token();
-
- // Return the contents of any current //extern comment.
- const std::string&
- extern_name() const
- { return this->extern_; }
-
- // Return whether we have seen a //go:nointerface comment, clearing
- // the flag.
- bool
- get_and_clear_nointerface()
- {
- bool ret = this->saw_nointerface_;
- this->saw_nointerface_ = false;
- return ret;
- }
-
- // Return whether the identifier NAME should be exported. NAME is a
- // mangled name which includes only ASCII characters.
- static bool
- is_exported_name(const std::string& name);
-
- // Return whether the identifier NAME is invalid. When we see an
- // invalid character we still build an identifier, but we use a
- // magic string to indicate that the identifier is invalid. We then
- // use this to avoid knockon errors.
- static bool
- is_invalid_identifier(const std::string& name);
-
- // A helper function. Append V to STR. IS_CHARACTER is true if V
- // is a Unicode character which should be converted into UTF-8,
- // false if it is a byte value to be appended directly. The
- // location is used to warn about an out of range character.
- static void
- append_char(unsigned int v, bool is_charater, std::string* str,
- Location);
-
- // A helper function. Fetch a UTF-8 character from STR and store it
- // in *VALUE. Return the number of bytes read from STR. Return 0
- // if STR does not point to a valid UTF-8 character.
- static int
- fetch_char(const char* str, unsigned int *value);
-
- // Return whether C is a Unicode or "C" locale space character.
- static bool
- is_unicode_space(unsigned int c);
-
- private:
- ssize_t
- get_line();
-
- bool
- require_line();
-
- // The current location.
- Location
- location() const;
-
- // A position CHARS column positions before the current location.
- Location
- earlier_location(int chars) const;
-
- static bool
- is_hex_digit(char);
-
- static unsigned char
- octal_value(char c)
- { return c - '0'; }
-
- Token
- make_invalid_token()
- { return Token::make_invalid_token(this->location()); }
-
- Token
- make_eof_token()
- { return Token::make_eof_token(this->location()); }
-
- Token
- make_operator(Operator op, int chars)
- { return Token::make_operator_token(op, this->earlier_location(chars)); }
-
- Token
- gather_identifier();
-
- static bool
- could_be_exponent(const char*, const char*);
-
- Token
- gather_number();
-
- Token
- gather_character();
-
- Token
- gather_string();
-
- Token
- gather_raw_string();
-
- const char*
- advance_one_utf8_char(const char*, unsigned int*, bool*);
-
- const char*
- advance_one_char(const char*, bool, unsigned int*, bool*);
-
- static bool
- is_unicode_digit(unsigned int c);
-
- static bool
- is_unicode_letter(unsigned int c);
-
- static bool
- is_unicode_uppercase(unsigned int c);
-
- static bool
- is_in_unicode_range(unsigned int C, const Unicode_range* ranges,
- size_t range_size);
-
- Operator
- three_character_operator(char, char, char);
-
- Operator
- two_character_operator(char, char);
-
- Operator
- one_character_operator(char);
-
- bool
- skip_c_comment();
-
- void
- skip_cpp_comment();
-
- // The input file name.
- const char* input_file_name_;
- // The input file.
- FILE* input_file_;
- // The object used to keep track of file names and line numbers.
- Linemap* linemap_;
- // The line buffer. This holds the current line.
- char* linebuf_;
- // The size of the line buffer.
- size_t linebufsize_;
- // The nmber of characters in the current line.
- size_t linesize_;
- // The current offset in linebuf_.
- size_t lineoff_;
- // The current line number.
- size_t lineno_;
- // Whether to add a semicolon if we see a newline now.
- bool add_semi_at_eol_;
- // Whether we just saw a magic go:nointerface comment.
- bool saw_nointerface_;
- // The external name to use for a function declaration, from a magic
- // //extern comment.
- std::string extern_;
-};
-
-#endif // !defined(GO_LEX_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/operator.h b/gcc-4.8.1/gcc/go/gofrontend/operator.h
deleted file mode 100644
index f3e0fd074..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/operator.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// operator.h -- Go frontend operators. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_OPERATOR_H
-#define GO_OPERATOR_H
-
-// The operators.
-
-enum Operator
-{
- OPERATOR_INVALID,
- OPERATOR_OROR, // ||
- OPERATOR_ANDAND, // &&
- OPERATOR_EQEQ, // ==
- OPERATOR_NOTEQ, // !=
- OPERATOR_LT, // <
- OPERATOR_LE, // <=
- OPERATOR_GT, // >
- OPERATOR_GE, // >=
- OPERATOR_PLUS, // +
- OPERATOR_MINUS, // -
- OPERATOR_OR, // |
- OPERATOR_XOR, // ^
- OPERATOR_MULT, // *
- OPERATOR_DIV, // /
- OPERATOR_MOD, // %
- OPERATOR_LSHIFT, // <<
- OPERATOR_RSHIFT, // >>
- OPERATOR_AND, // &
- OPERATOR_NOT, // !
- OPERATOR_BITCLEAR, // &^
- OPERATOR_CHANOP, // <-
-
- OPERATOR_EQ, // =
- OPERATOR_PLUSEQ, // +=
- OPERATOR_MINUSEQ, // -=
- OPERATOR_OREQ, // |=
- OPERATOR_XOREQ, // ^=
- OPERATOR_MULTEQ, // *=
- OPERATOR_DIVEQ, // /=
- OPERATOR_MODEQ, // %=
- OPERATOR_LSHIFTEQ, // <<=
- OPERATOR_RSHIFTEQ, // >>=
- OPERATOR_ANDEQ, // &=
- OPERATOR_BITCLEAREQ, // &^=
- OPERATOR_PLUSPLUS, // ++
- OPERATOR_MINUSMINUS, // --
-
- OPERATOR_COLON, // :
- OPERATOR_COLONEQ, // :=
- OPERATOR_SEMICOLON, // ;
- OPERATOR_DOT, // .
- OPERATOR_ELLIPSIS, // ...
- OPERATOR_COMMA, // ,
- OPERATOR_LPAREN, // (
- OPERATOR_RPAREN, // )
- OPERATOR_LCURLY, // {
- OPERATOR_RCURLY, // }
- OPERATOR_LSQUARE, // [
- OPERATOR_RSQUARE // ]
-};
-
-#endif // !defined(GO_OPERATOR_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/parse.cc b/gcc-4.8.1/gcc/go/gofrontend/parse.cc
deleted file mode 100644
index d7a18d023..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/parse.cc
+++ /dev/null
@@ -1,5676 +0,0 @@
-// parse.cc -- Go frontend parser.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "lex.h"
-#include "gogo.h"
-#include "types.h"
-#include "statements.h"
-#include "expressions.h"
-#include "parse.h"
-
-// Struct Parse::Enclosing_var_comparison.
-
-// Return true if v1 should be considered to be less than v2.
-
-bool
-Parse::Enclosing_var_comparison::operator()(const Enclosing_var& v1,
- const Enclosing_var& v2)
-{
- if (v1.var() == v2.var())
- return false;
-
- const std::string& n1(v1.var()->name());
- const std::string& n2(v2.var()->name());
- int i = n1.compare(n2);
- if (i < 0)
- return true;
- else if (i > 0)
- return false;
-
- // If we get here it means that a single nested function refers to
- // two different variables defined in enclosing functions, and both
- // variables have the same name. I think this is impossible.
- go_unreachable();
-}
-
-// Class Parse.
-
-Parse::Parse(Lex* lex, Gogo* gogo)
- : lex_(lex),
- token_(Token::make_invalid_token(Linemap::unknown_location())),
- unget_token_(Token::make_invalid_token(Linemap::unknown_location())),
- unget_token_valid_(false),
- is_erroneous_function_(false),
- gogo_(gogo),
- break_stack_(NULL),
- continue_stack_(NULL),
- iota_(0),
- enclosing_vars_(),
- type_switch_vars_()
-{
-}
-
-// Return the current token.
-
-const Token*
-Parse::peek_token()
-{
- if (this->unget_token_valid_)
- return &this->unget_token_;
- if (this->token_.is_invalid())
- this->token_ = this->lex_->next_token();
- return &this->token_;
-}
-
-// Advance to the next token and return it.
-
-const Token*
-Parse::advance_token()
-{
- if (this->unget_token_valid_)
- {
- this->unget_token_valid_ = false;
- if (!this->token_.is_invalid())
- return &this->token_;
- }
- this->token_ = this->lex_->next_token();
- return &this->token_;
-}
-
-// Push a token back on the input stream.
-
-void
-Parse::unget_token(const Token& token)
-{
- go_assert(!this->unget_token_valid_);
- this->unget_token_ = token;
- this->unget_token_valid_ = true;
-}
-
-// The location of the current token.
-
-Location
-Parse::location()
-{
- return this->peek_token()->location();
-}
-
-// IdentifierList = identifier { "," identifier } .
-
-void
-Parse::identifier_list(Typed_identifier_list* til)
-{
- const Token* token = this->peek_token();
- while (true)
- {
- if (!token->is_identifier())
- {
- error_at(this->location(), "expected identifier");
- return;
- }
- std::string name =
- this->gogo_->pack_hidden_name(token->identifier(),
- token->is_identifier_exported());
- til->push_back(Typed_identifier(name, NULL, token->location()));
- token = this->advance_token();
- if (!token->is_op(OPERATOR_COMMA))
- return;
- token = this->advance_token();
- }
-}
-
-// ExpressionList = Expression { "," Expression } .
-
-// If MAY_BE_COMPOSITE_LIT is true, an expression may be a composite
-// literal.
-
-// If MAY_BE_SINK is true, the expressions in the list may be "_".
-
-Expression_list*
-Parse::expression_list(Expression* first, bool may_be_sink,
- bool may_be_composite_lit)
-{
- Expression_list* ret = new Expression_list();
- if (first != NULL)
- ret->push_back(first);
- while (true)
- {
- ret->push_back(this->expression(PRECEDENCE_NORMAL, may_be_sink,
- may_be_composite_lit, NULL, NULL));
-
- const Token* token = this->peek_token();
- if (!token->is_op(OPERATOR_COMMA))
- return ret;
-
- // Most expression lists permit a trailing comma.
- Location location = token->location();
- this->advance_token();
- if (!this->expression_may_start_here())
- {
- this->unget_token(Token::make_operator_token(OPERATOR_COMMA,
- location));
- return ret;
- }
- }
-}
-
-// QualifiedIdent = [ PackageName "." ] identifier .
-// PackageName = identifier .
-
-// This sets *PNAME to the identifier and sets *PPACKAGE to the
-// package or NULL if there isn't one. This returns true on success,
-// false on failure in which case it will have emitted an error
-// message.
-
-bool
-Parse::qualified_ident(std::string* pname, Named_object** ppackage)
-{
- const Token* token = this->peek_token();
- if (!token->is_identifier())
- {
- error_at(this->location(), "expected identifier");
- return false;
- }
-
- std::string name = token->identifier();
- bool is_exported = token->is_identifier_exported();
- name = this->gogo_->pack_hidden_name(name, is_exported);
-
- token = this->advance_token();
- if (!token->is_op(OPERATOR_DOT))
- {
- *pname = name;
- *ppackage = NULL;
- return true;
- }
-
- Named_object* package = this->gogo_->lookup(name, NULL);
- if (package == NULL || !package->is_package())
- {
- error_at(this->location(), "expected package");
- // We expect . IDENTIFIER; skip both.
- if (this->advance_token()->is_identifier())
- this->advance_token();
- return false;
- }
-
- package->package_value()->set_used();
-
- token = this->advance_token();
- if (!token->is_identifier())
- {
- error_at(this->location(), "expected identifier");
- return false;
- }
-
- name = token->identifier();
-
- if (name == "_")
- {
- error_at(this->location(), "invalid use of %<_%>");
- name = "blank";
- }
-
- if (package->name() == this->gogo_->package_name())
- name = this->gogo_->pack_hidden_name(name,
- token->is_identifier_exported());
-
- *pname = name;
- *ppackage = package;
-
- this->advance_token();
-
- return true;
-}
-
-// Type = TypeName | TypeLit | "(" Type ")" .
-// TypeLit =
-// ArrayType | StructType | PointerType | FunctionType | InterfaceType |
-// SliceType | MapType | ChannelType .
-
-Type*
-Parse::type()
-{
- const Token* token = this->peek_token();
- if (token->is_identifier())
- return this->type_name(true);
- else if (token->is_op(OPERATOR_LSQUARE))
- return this->array_type(false);
- else if (token->is_keyword(KEYWORD_CHAN)
- || token->is_op(OPERATOR_CHANOP))
- return this->channel_type();
- else if (token->is_keyword(KEYWORD_INTERFACE))
- return this->interface_type();
- else if (token->is_keyword(KEYWORD_FUNC))
- {
- Location location = token->location();
- this->advance_token();
- Type* type = this->signature(NULL, location);
- if (type == NULL)
- return Type::make_error_type();
- return type;
- }
- else if (token->is_keyword(KEYWORD_MAP))
- return this->map_type();
- else if (token->is_keyword(KEYWORD_STRUCT))
- return this->struct_type();
- else if (token->is_op(OPERATOR_MULT))
- return this->pointer_type();
- else if (token->is_op(OPERATOR_LPAREN))
- {
- this->advance_token();
- Type* ret = this->type();
- if (this->peek_token()->is_op(OPERATOR_RPAREN))
- this->advance_token();
- else
- {
- if (!ret->is_error_type())
- error_at(this->location(), "expected %<)%>");
- }
- return ret;
- }
- else
- {
- error_at(token->location(), "expected type");
- return Type::make_error_type();
- }
-}
-
-bool
-Parse::type_may_start_here()
-{
- const Token* token = this->peek_token();
- return (token->is_identifier()
- || token->is_op(OPERATOR_LSQUARE)
- || token->is_op(OPERATOR_CHANOP)
- || token->is_keyword(KEYWORD_CHAN)
- || token->is_keyword(KEYWORD_INTERFACE)
- || token->is_keyword(KEYWORD_FUNC)
- || token->is_keyword(KEYWORD_MAP)
- || token->is_keyword(KEYWORD_STRUCT)
- || token->is_op(OPERATOR_MULT)
- || token->is_op(OPERATOR_LPAREN));
-}
-
-// TypeName = QualifiedIdent .
-
-// If MAY_BE_NIL is true, then an identifier with the value of the
-// predefined constant nil is accepted, returning the nil type.
-
-Type*
-Parse::type_name(bool issue_error)
-{
- Location location = this->location();
-
- std::string name;
- Named_object* package;
- if (!this->qualified_ident(&name, &package))
- return Type::make_error_type();
-
- Named_object* named_object;
- if (package == NULL)
- named_object = this->gogo_->lookup(name, NULL);
- else
- {
- named_object = package->package_value()->lookup(name);
- if (named_object == NULL
- && issue_error
- && package->name() != this->gogo_->package_name())
- {
- // Check whether the name is there but hidden.
- std::string s = ('.' + package->package_value()->pkgpath()
- + '.' + name);
- named_object = package->package_value()->lookup(s);
- if (named_object != NULL)
- {
- Package* p = package->package_value();
- const std::string& packname(p->package_name());
- error_at(location, "invalid reference to hidden type %<%s.%s%>",
- Gogo::message_name(packname).c_str(),
- Gogo::message_name(name).c_str());
- issue_error = false;
- }
- }
- }
-
- bool ok = true;
- if (named_object == NULL)
- {
- if (package == NULL)
- named_object = this->gogo_->add_unknown_name(name, location);
- else
- {
- const std::string& packname(package->package_value()->package_name());
- error_at(location, "reference to undefined identifier %<%s.%s%>",
- Gogo::message_name(packname).c_str(),
- Gogo::message_name(name).c_str());
- issue_error = false;
- ok = false;
- }
- }
- else if (named_object->is_type())
- {
- if (!named_object->type_value()->is_visible())
- ok = false;
- }
- else if (named_object->is_unknown() || named_object->is_type_declaration())
- ;
- else
- ok = false;
-
- if (!ok)
- {
- if (issue_error)
- error_at(location, "expected type");
- return Type::make_error_type();
- }
-
- if (named_object->is_type())
- return named_object->type_value();
- else if (named_object->is_unknown() || named_object->is_type_declaration())
- return Type::make_forward_declaration(named_object);
- else
- go_unreachable();
-}
-
-// ArrayType = "[" [ ArrayLength ] "]" ElementType .
-// ArrayLength = Expression .
-// ElementType = CompleteType .
-
-Type*
-Parse::array_type(bool may_use_ellipsis)
-{
- go_assert(this->peek_token()->is_op(OPERATOR_LSQUARE));
- const Token* token = this->advance_token();
-
- Expression* length = NULL;
- if (token->is_op(OPERATOR_RSQUARE))
- this->advance_token();
- else
- {
- if (!token->is_op(OPERATOR_ELLIPSIS))
- length = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
- else if (may_use_ellipsis)
- {
- // An ellipsis is used in composite literals to represent a
- // fixed array of the size of the number of elements. We
- // use a length of nil to represent this, and change the
- // length when parsing the composite literal.
- length = Expression::make_nil(this->location());
- this->advance_token();
- }
- else
- {
- error_at(this->location(),
- "use of %<[...]%> outside of array literal");
- length = Expression::make_error(this->location());
- this->advance_token();
- }
- if (!this->peek_token()->is_op(OPERATOR_RSQUARE))
- {
- error_at(this->location(), "expected %<]%>");
- return Type::make_error_type();
- }
- this->advance_token();
- }
-
- Type* element_type = this->type();
-
- return Type::make_array_type(element_type, length);
-}
-
-// MapType = "map" "[" KeyType "]" ValueType .
-// KeyType = CompleteType .
-// ValueType = CompleteType .
-
-Type*
-Parse::map_type()
-{
- Location location = this->location();
- go_assert(this->peek_token()->is_keyword(KEYWORD_MAP));
- if (!this->advance_token()->is_op(OPERATOR_LSQUARE))
- {
- error_at(this->location(), "expected %<[%>");
- return Type::make_error_type();
- }
- this->advance_token();
-
- Type* key_type = this->type();
-
- if (!this->peek_token()->is_op(OPERATOR_RSQUARE))
- {
- error_at(this->location(), "expected %<]%>");
- return Type::make_error_type();
- }
- this->advance_token();
-
- Type* value_type = this->type();
-
- if (key_type->is_error_type() || value_type->is_error_type())
- return Type::make_error_type();
-
- return Type::make_map_type(key_type, value_type, location);
-}
-
-// StructType = "struct" "{" { FieldDecl ";" } "}" .
-
-Type*
-Parse::struct_type()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_STRUCT));
- Location location = this->location();
- if (!this->advance_token()->is_op(OPERATOR_LCURLY))
- {
- Location token_loc = this->location();
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON)
- && this->advance_token()->is_op(OPERATOR_LCURLY))
- error_at(token_loc, "unexpected semicolon or newline before %<{%>");
- else
- {
- error_at(this->location(), "expected %<{%>");
- return Type::make_error_type();
- }
- }
- this->advance_token();
-
- Struct_field_list* sfl = new Struct_field_list;
- while (!this->peek_token()->is_op(OPERATOR_RCURLY))
- {
- this->field_decl(sfl);
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- this->advance_token();
- else if (!this->peek_token()->is_op(OPERATOR_RCURLY))
- {
- error_at(this->location(), "expected %<;%> or %<}%> or newline");
- if (!this->skip_past_error(OPERATOR_RCURLY))
- return Type::make_error_type();
- }
- }
- this->advance_token();
-
- for (Struct_field_list::const_iterator pi = sfl->begin();
- pi != sfl->end();
- ++pi)
- {
- if (pi->type()->is_error_type())
- return pi->type();
- for (Struct_field_list::const_iterator pj = pi + 1;
- pj != sfl->end();
- ++pj)
- {
- if (pi->field_name() == pj->field_name()
- && !Gogo::is_sink_name(pi->field_name()))
- error_at(pi->location(), "duplicate field name %<%s%>",
- Gogo::message_name(pi->field_name()).c_str());
- }
- }
-
- return Type::make_struct_type(sfl, location);
-}
-
-// FieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] .
-// Tag = string_lit .
-
-void
-Parse::field_decl(Struct_field_list* sfl)
-{
- const Token* token = this->peek_token();
- Location location = token->location();
- bool is_anonymous;
- bool is_anonymous_pointer;
- if (token->is_op(OPERATOR_MULT))
- {
- is_anonymous = true;
- is_anonymous_pointer = true;
- }
- else if (token->is_identifier())
- {
- std::string id = token->identifier();
- bool is_id_exported = token->is_identifier_exported();
- Location id_location = token->location();
- token = this->advance_token();
- is_anonymous = (token->is_op(OPERATOR_SEMICOLON)
- || token->is_op(OPERATOR_RCURLY)
- || token->is_op(OPERATOR_DOT)
- || token->is_string());
- is_anonymous_pointer = false;
- this->unget_token(Token::make_identifier_token(id, is_id_exported,
- id_location));
- }
- else
- {
- error_at(this->location(), "expected field name");
- this->gogo_->mark_locals_used();
- while (!token->is_op(OPERATOR_SEMICOLON)
- && !token->is_op(OPERATOR_RCURLY)
- && !token->is_eof())
- token = this->advance_token();
- return;
- }
-
- if (is_anonymous)
- {
- if (is_anonymous_pointer)
- {
- this->advance_token();
- if (!this->peek_token()->is_identifier())
- {
- error_at(this->location(), "expected field name");
- this->gogo_->mark_locals_used();
- while (!token->is_op(OPERATOR_SEMICOLON)
- && !token->is_op(OPERATOR_RCURLY)
- && !token->is_eof())
- token = this->advance_token();
- return;
- }
- }
- Type* type = this->type_name(true);
-
- std::string tag;
- if (this->peek_token()->is_string())
- {
- tag = this->peek_token()->string_value();
- this->advance_token();
- }
-
- if (!type->is_error_type())
- {
- if (is_anonymous_pointer)
- type = Type::make_pointer_type(type);
- sfl->push_back(Struct_field(Typed_identifier("", type, location)));
- if (!tag.empty())
- sfl->back().set_tag(tag);
- }
- }
- else
- {
- Typed_identifier_list til;
- while (true)
- {
- token = this->peek_token();
- if (!token->is_identifier())
- {
- error_at(this->location(), "expected identifier");
- return;
- }
- std::string name =
- this->gogo_->pack_hidden_name(token->identifier(),
- token->is_identifier_exported());
- til.push_back(Typed_identifier(name, NULL, token->location()));
- if (!this->advance_token()->is_op(OPERATOR_COMMA))
- break;
- this->advance_token();
- }
-
- Type* type = this->type();
-
- std::string tag;
- if (this->peek_token()->is_string())
- {
- tag = this->peek_token()->string_value();
- this->advance_token();
- }
-
- for (Typed_identifier_list::iterator p = til.begin();
- p != til.end();
- ++p)
- {
- p->set_type(type);
- sfl->push_back(Struct_field(*p));
- if (!tag.empty())
- sfl->back().set_tag(tag);
- }
- }
-}
-
-// PointerType = "*" Type .
-
-Type*
-Parse::pointer_type()
-{
- go_assert(this->peek_token()->is_op(OPERATOR_MULT));
- this->advance_token();
- Type* type = this->type();
- if (type->is_error_type())
- return type;
- return Type::make_pointer_type(type);
-}
-
-// ChannelType = Channel | SendChannel | RecvChannel .
-// Channel = "chan" ElementType .
-// SendChannel = "chan" "<-" ElementType .
-// RecvChannel = "<-" "chan" ElementType .
-
-Type*
-Parse::channel_type()
-{
- const Token* token = this->peek_token();
- bool send = true;
- bool receive = true;
- if (token->is_op(OPERATOR_CHANOP))
- {
- if (!this->advance_token()->is_keyword(KEYWORD_CHAN))
- {
- error_at(this->location(), "expected %<chan%>");
- return Type::make_error_type();
- }
- send = false;
- this->advance_token();
- }
- else
- {
- go_assert(token->is_keyword(KEYWORD_CHAN));
- if (this->advance_token()->is_op(OPERATOR_CHANOP))
- {
- receive = false;
- this->advance_token();
- }
- }
-
- // Better error messages for the common error of omitting the
- // channel element type.
- if (!this->type_may_start_here())
- {
- token = this->peek_token();
- if (token->is_op(OPERATOR_RCURLY))
- error_at(this->location(), "unexpected %<}%> in channel type");
- else if (token->is_op(OPERATOR_RPAREN))
- error_at(this->location(), "unexpected %<)%> in channel type");
- else if (token->is_op(OPERATOR_COMMA))
- error_at(this->location(), "unexpected comma in channel type");
- else
- error_at(this->location(), "expected channel element type");
- return Type::make_error_type();
- }
-
- Type* element_type = this->type();
- return Type::make_channel_type(send, receive, element_type);
-}
-
-// Give an error for a duplicate parameter or receiver name.
-
-void
-Parse::check_signature_names(const Typed_identifier_list* params,
- Parse::Names* names)
-{
- for (Typed_identifier_list::const_iterator p = params->begin();
- p != params->end();
- ++p)
- {
- if (p->name().empty() || Gogo::is_sink_name(p->name()))
- continue;
- std::pair<std::string, const Typed_identifier*> val =
- std::make_pair(p->name(), &*p);
- std::pair<Parse::Names::iterator, bool> ins = names->insert(val);
- if (!ins.second)
- {
- error_at(p->location(), "redefinition of %qs",
- Gogo::message_name(p->name()).c_str());
- inform(ins.first->second->location(),
- "previous definition of %qs was here",
- Gogo::message_name(p->name()).c_str());
- }
- }
-}
-
-// Signature = Parameters [ Result ] .
-
-// RECEIVER is the receiver if there is one, or NULL. LOCATION is the
-// location of the start of the type.
-
-// This returns NULL on a parse error.
-
-Function_type*
-Parse::signature(Typed_identifier* receiver, Location location)
-{
- bool is_varargs = false;
- Typed_identifier_list* params;
- bool params_ok = this->parameters(&params, &is_varargs);
-
- Typed_identifier_list* results = NULL;
- if (this->peek_token()->is_op(OPERATOR_LPAREN)
- || this->type_may_start_here())
- {
- if (!this->result(&results))
- return NULL;
- }
-
- if (!params_ok)
- return NULL;
-
- Parse::Names names;
- if (params != NULL)
- this->check_signature_names(params, &names);
- if (results != NULL)
- this->check_signature_names(results, &names);
-
- Function_type* ret = Type::make_function_type(receiver, params, results,
- location);
- if (is_varargs)
- ret->set_is_varargs();
- return ret;
-}
-
-// Parameters = "(" [ ParameterList [ "," ] ] ")" .
-
-// This returns false on a parse error.
-
-bool
-Parse::parameters(Typed_identifier_list** pparams, bool* is_varargs)
-{
- *pparams = NULL;
-
- if (!this->peek_token()->is_op(OPERATOR_LPAREN))
- {
- error_at(this->location(), "expected %<(%>");
- return false;
- }
-
- Typed_identifier_list* params = NULL;
- bool saw_error = false;
-
- const Token* token = this->advance_token();
- if (!token->is_op(OPERATOR_RPAREN))
- {
- params = this->parameter_list(is_varargs);
- if (params == NULL)
- saw_error = true;
- token = this->peek_token();
- }
-
- // The optional trailing comma is picked up in parameter_list.
-
- if (!token->is_op(OPERATOR_RPAREN))
- error_at(this->location(), "expected %<)%>");
- else
- this->advance_token();
-
- if (saw_error)
- return false;
-
- *pparams = params;
- return true;
-}
-
-// ParameterList = ParameterDecl { "," ParameterDecl } .
-
-// This sets *IS_VARARGS if the list ends with an ellipsis.
-// IS_VARARGS will be NULL if varargs are not permitted.
-
-// We pick up an optional trailing comma.
-
-// This returns NULL if some error is seen.
-
-Typed_identifier_list*
-Parse::parameter_list(bool* is_varargs)
-{
- Location location = this->location();
- Typed_identifier_list* ret = new Typed_identifier_list();
-
- bool saw_error = false;
-
- // If we see an identifier and then a comma, then we don't know
- // whether we are looking at a list of identifiers followed by a
- // type, or a list of types given by name. We have to do an
- // arbitrary lookahead to figure it out.
-
- bool parameters_have_names;
- const Token* token = this->peek_token();
- if (!token->is_identifier())
- {
- // This must be a type which starts with something like '*'.
- parameters_have_names = false;
- }
- else
- {
- std::string name = token->identifier();
- bool is_exported = token->is_identifier_exported();
- Location location = token->location();
- token = this->advance_token();
- if (!token->is_op(OPERATOR_COMMA))
- {
- if (token->is_op(OPERATOR_DOT))
- {
- // This is a qualified identifier, which must turn out
- // to be a type.
- parameters_have_names = false;
- }
- else if (token->is_op(OPERATOR_RPAREN))
- {
- // A single identifier followed by a parenthesis must be
- // a type name.
- parameters_have_names = false;
- }
- else
- {
- // An identifier followed by something other than a
- // comma or a dot or a right parenthesis must be a
- // parameter name followed by a type.
- parameters_have_names = true;
- }
-
- this->unget_token(Token::make_identifier_token(name, is_exported,
- location));
- }
- else
- {
- // An identifier followed by a comma may be the first in a
- // list of parameter names followed by a type, or it may be
- // the first in a list of types without parameter names. To
- // find out we gather as many identifiers separated by
- // commas as we can.
- std::string id_name = this->gogo_->pack_hidden_name(name,
- is_exported);
- ret->push_back(Typed_identifier(id_name, NULL, location));
- bool just_saw_comma = true;
- while (this->advance_token()->is_identifier())
- {
- name = this->peek_token()->identifier();
- is_exported = this->peek_token()->is_identifier_exported();
- location = this->peek_token()->location();
- id_name = this->gogo_->pack_hidden_name(name, is_exported);
- ret->push_back(Typed_identifier(id_name, NULL, location));
- if (!this->advance_token()->is_op(OPERATOR_COMMA))
- {
- just_saw_comma = false;
- break;
- }
- }
-
- if (just_saw_comma)
- {
- // We saw ID1 "," ID2 "," followed by something which
- // was not an identifier. We must be seeing the start
- // of a type, and ID1 and ID2 must be types, and the
- // parameters don't have names.
- parameters_have_names = false;
- }
- else if (this->peek_token()->is_op(OPERATOR_RPAREN))
- {
- // We saw ID1 "," ID2 ")". ID1 and ID2 must be types,
- // and the parameters don't have names.
- parameters_have_names = false;
- }
- else if (this->peek_token()->is_op(OPERATOR_DOT))
- {
- // We saw ID1 "," ID2 ".". ID2 must be a package name,
- // ID1 must be a type, and the parameters don't have
- // names.
- parameters_have_names = false;
- this->unget_token(Token::make_identifier_token(name, is_exported,
- location));
- ret->pop_back();
- just_saw_comma = true;
- }
- else
- {
- // We saw ID1 "," ID2 followed by something other than
- // ",", ".", or ")". We must be looking at the start of
- // a type, and ID1 and ID2 must be parameter names.
- parameters_have_names = true;
- }
-
- if (parameters_have_names)
- {
- go_assert(!just_saw_comma);
- // We have just seen ID1, ID2 xxx.
- Type* type;
- if (!this->peek_token()->is_op(OPERATOR_ELLIPSIS))
- type = this->type();
- else
- {
- error_at(this->location(), "%<...%> only permits one name");
- saw_error = true;
- this->advance_token();
- type = this->type();
- }
- for (size_t i = 0; i < ret->size(); ++i)
- ret->set_type(i, type);
- if (!this->peek_token()->is_op(OPERATOR_COMMA))
- return saw_error ? NULL : ret;
- if (this->advance_token()->is_op(OPERATOR_RPAREN))
- return saw_error ? NULL : ret;
- }
- else
- {
- Typed_identifier_list* tret = new Typed_identifier_list();
- for (Typed_identifier_list::const_iterator p = ret->begin();
- p != ret->end();
- ++p)
- {
- Named_object* no = this->gogo_->lookup(p->name(), NULL);
- Type* type;
- if (no == NULL)
- no = this->gogo_->add_unknown_name(p->name(),
- p->location());
-
- if (no->is_type())
- type = no->type_value();
- else if (no->is_unknown() || no->is_type_declaration())
- type = Type::make_forward_declaration(no);
- else
- {
- error_at(p->location(), "expected %<%s%> to be a type",
- Gogo::message_name(p->name()).c_str());
- saw_error = true;
- type = Type::make_error_type();
- }
- tret->push_back(Typed_identifier("", type, p->location()));
- }
- delete ret;
- ret = tret;
- if (!just_saw_comma
- || this->peek_token()->is_op(OPERATOR_RPAREN))
- return saw_error ? NULL : ret;
- }
- }
- }
-
- bool mix_error = false;
- this->parameter_decl(parameters_have_names, ret, is_varargs, &mix_error);
- while (this->peek_token()->is_op(OPERATOR_COMMA))
- {
- if (this->advance_token()->is_op(OPERATOR_RPAREN))
- break;
- if (is_varargs != NULL && *is_varargs)
- {
- error_at(this->location(), "%<...%> must be last parameter");
- saw_error = true;
- }
- this->parameter_decl(parameters_have_names, ret, is_varargs, &mix_error);
- }
- if (mix_error)
- {
- error_at(location, "invalid named/anonymous mix");
- saw_error = true;
- }
- if (saw_error)
- {
- delete ret;
- return NULL;
- }
- return ret;
-}
-
-// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
-
-void
-Parse::parameter_decl(bool parameters_have_names,
- Typed_identifier_list* til,
- bool* is_varargs,
- bool* mix_error)
-{
- if (!parameters_have_names)
- {
- Type* type;
- Location location = this->location();
- if (!this->peek_token()->is_identifier())
- {
- if (!this->peek_token()->is_op(OPERATOR_ELLIPSIS))
- type = this->type();
- else
- {
- if (is_varargs == NULL)
- error_at(this->location(), "invalid use of %<...%>");
- else
- *is_varargs = true;
- this->advance_token();
- if (is_varargs == NULL
- && this->peek_token()->is_op(OPERATOR_RPAREN))
- type = Type::make_error_type();
- else
- {
- Type* element_type = this->type();
- type = Type::make_array_type(element_type, NULL);
- }
- }
- }
- else
- {
- type = this->type_name(false);
- if (type->is_error_type()
- || (!this->peek_token()->is_op(OPERATOR_COMMA)
- && !this->peek_token()->is_op(OPERATOR_RPAREN)))
- {
- *mix_error = true;
- while (!this->peek_token()->is_op(OPERATOR_COMMA)
- && !this->peek_token()->is_op(OPERATOR_RPAREN))
- this->advance_token();
- }
- }
- if (!type->is_error_type())
- til->push_back(Typed_identifier("", type, location));
- }
- else
- {
- size_t orig_count = til->size();
- if (this->peek_token()->is_identifier())
- this->identifier_list(til);
- else
- *mix_error = true;
- size_t new_count = til->size();
-
- Type* type;
- if (!this->peek_token()->is_op(OPERATOR_ELLIPSIS))
- type = this->type();
- else
- {
- if (is_varargs == NULL)
- error_at(this->location(), "invalid use of %<...%>");
- else if (new_count > orig_count + 1)
- error_at(this->location(), "%<...%> only permits one name");
- else
- *is_varargs = true;
- this->advance_token();
- Type* element_type = this->type();
- type = Type::make_array_type(element_type, NULL);
- }
- for (size_t i = orig_count; i < new_count; ++i)
- til->set_type(i, type);
- }
-}
-
-// Result = Parameters | Type .
-
-// This returns false on a parse error.
-
-bool
-Parse::result(Typed_identifier_list** presults)
-{
- if (this->peek_token()->is_op(OPERATOR_LPAREN))
- return this->parameters(presults, NULL);
- else
- {
- Location location = this->location();
- Type* type = this->type();
- if (type->is_error_type())
- {
- *presults = NULL;
- return false;
- }
- Typed_identifier_list* til = new Typed_identifier_list();
- til->push_back(Typed_identifier("", type, location));
- *presults = til;
- return true;
- }
-}
-
-// Block = "{" [ StatementList ] "}" .
-
-// Returns the location of the closing brace.
-
-Location
-Parse::block()
-{
- if (!this->peek_token()->is_op(OPERATOR_LCURLY))
- {
- Location loc = this->location();
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON)
- && this->advance_token()->is_op(OPERATOR_LCURLY))
- error_at(loc, "unexpected semicolon or newline before %<{%>");
- else
- {
- error_at(this->location(), "expected %<{%>");
- return Linemap::unknown_location();
- }
- }
-
- const Token* token = this->advance_token();
-
- if (!token->is_op(OPERATOR_RCURLY))
- {
- this->statement_list();
- token = this->peek_token();
- if (!token->is_op(OPERATOR_RCURLY))
- {
- if (!token->is_eof() || !saw_errors())
- error_at(this->location(), "expected %<}%>");
-
- this->gogo_->mark_locals_used();
-
- // Skip ahead to the end of the block, in hopes of avoiding
- // lots of meaningless errors.
- Location ret = token->location();
- int nest = 0;
- while (!token->is_eof())
- {
- if (token->is_op(OPERATOR_LCURLY))
- ++nest;
- else if (token->is_op(OPERATOR_RCURLY))
- {
- --nest;
- if (nest < 0)
- {
- this->advance_token();
- break;
- }
- }
- token = this->advance_token();
- ret = token->location();
- }
- return ret;
- }
- }
-
- Location ret = token->location();
- this->advance_token();
- return ret;
-}
-
-// InterfaceType = "interface" "{" [ MethodSpecList ] "}" .
-// MethodSpecList = MethodSpec { ";" MethodSpec } [ ";" ] .
-
-Type*
-Parse::interface_type()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_INTERFACE));
- Location location = this->location();
-
- if (!this->advance_token()->is_op(OPERATOR_LCURLY))
- {
- Location token_loc = this->location();
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON)
- && this->advance_token()->is_op(OPERATOR_LCURLY))
- error_at(token_loc, "unexpected semicolon or newline before %<{%>");
- else
- {
- error_at(this->location(), "expected %<{%>");
- return Type::make_error_type();
- }
- }
- this->advance_token();
-
- Typed_identifier_list* methods = new Typed_identifier_list();
- if (!this->peek_token()->is_op(OPERATOR_RCURLY))
- {
- this->method_spec(methods);
- while (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- {
- if (this->advance_token()->is_op(OPERATOR_RCURLY))
- break;
- this->method_spec(methods);
- }
- if (!this->peek_token()->is_op(OPERATOR_RCURLY))
- {
- error_at(this->location(), "expected %<}%>");
- while (!this->advance_token()->is_op(OPERATOR_RCURLY))
- {
- if (this->peek_token()->is_eof())
- return Type::make_error_type();
- }
- }
- }
- this->advance_token();
-
- if (methods->empty())
- {
- delete methods;
- methods = NULL;
- }
-
- Interface_type* ret = Type::make_interface_type(methods, location);
- this->gogo_->record_interface_type(ret);
- return ret;
-}
-
-// MethodSpec = MethodName Signature | InterfaceTypeName .
-// MethodName = identifier .
-// InterfaceTypeName = TypeName .
-
-void
-Parse::method_spec(Typed_identifier_list* methods)
-{
- const Token* token = this->peek_token();
- if (!token->is_identifier())
- {
- error_at(this->location(), "expected identifier");
- return;
- }
-
- std::string name = token->identifier();
- bool is_exported = token->is_identifier_exported();
- Location location = token->location();
-
- if (this->advance_token()->is_op(OPERATOR_LPAREN))
- {
- // This is a MethodName.
- name = this->gogo_->pack_hidden_name(name, is_exported);
- Type* type = this->signature(NULL, location);
- if (type == NULL)
- return;
- methods->push_back(Typed_identifier(name, type, location));
- }
- else
- {
- this->unget_token(Token::make_identifier_token(name, is_exported,
- location));
- Type* type = this->type_name(false);
- if (type->is_error_type()
- || (!this->peek_token()->is_op(OPERATOR_SEMICOLON)
- && !this->peek_token()->is_op(OPERATOR_RCURLY)))
- {
- if (this->peek_token()->is_op(OPERATOR_COMMA))
- error_at(this->location(),
- "name list not allowed in interface type");
- else
- error_at(location, "expected signature or type name");
- this->gogo_->mark_locals_used();
- token = this->peek_token();
- while (!token->is_eof()
- && !token->is_op(OPERATOR_SEMICOLON)
- && !token->is_op(OPERATOR_RCURLY))
- token = this->advance_token();
- return;
- }
- // This must be an interface type, but we can't check that now.
- // We check it and pull out the methods in
- // Interface_type::do_verify.
- methods->push_back(Typed_identifier("", type, location));
- }
-}
-
-// Declaration = ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl .
-
-void
-Parse::declaration()
-{
- const Token* token = this->peek_token();
-
- bool saw_nointerface = this->lex_->get_and_clear_nointerface();
- if (saw_nointerface && !token->is_keyword(KEYWORD_FUNC))
- warning_at(token->location(), 0,
- "ignoring magic //go:nointerface comment before non-method");
-
- if (token->is_keyword(KEYWORD_CONST))
- this->const_decl();
- else if (token->is_keyword(KEYWORD_TYPE))
- this->type_decl();
- else if (token->is_keyword(KEYWORD_VAR))
- this->var_decl();
- else if (token->is_keyword(KEYWORD_FUNC))
- this->function_decl(saw_nointerface);
- else
- {
- error_at(this->location(), "expected declaration");
- this->advance_token();
- }
-}
-
-bool
-Parse::declaration_may_start_here()
-{
- const Token* token = this->peek_token();
- return (token->is_keyword(KEYWORD_CONST)
- || token->is_keyword(KEYWORD_TYPE)
- || token->is_keyword(KEYWORD_VAR)
- || token->is_keyword(KEYWORD_FUNC));
-}
-
-// Decl<P> = P | "(" [ List<P> ] ")" .
-
-void
-Parse::decl(void (Parse::*pfn)(void*), void* varg)
-{
- if (this->peek_token()->is_eof())
- {
- if (!saw_errors())
- error_at(this->location(), "unexpected end of file");
- return;
- }
-
- if (!this->peek_token()->is_op(OPERATOR_LPAREN))
- (this->*pfn)(varg);
- else
- {
- if (!this->advance_token()->is_op(OPERATOR_RPAREN))
- {
- this->list(pfn, varg, true);
- if (!this->peek_token()->is_op(OPERATOR_RPAREN))
- {
- error_at(this->location(), "missing %<)%>");
- while (!this->advance_token()->is_op(OPERATOR_RPAREN))
- {
- if (this->peek_token()->is_eof())
- return;
- }
- }
- }
- this->advance_token();
- }
-}
-
-// List<P> = P { ";" P } [ ";" ] .
-
-// In order to pick up the trailing semicolon we need to know what
-// might follow. This is either a '}' or a ')'.
-
-void
-Parse::list(void (Parse::*pfn)(void*), void* varg, bool follow_is_paren)
-{
- (this->*pfn)(varg);
- Operator follow = follow_is_paren ? OPERATOR_RPAREN : OPERATOR_RCURLY;
- while (this->peek_token()->is_op(OPERATOR_SEMICOLON)
- || this->peek_token()->is_op(OPERATOR_COMMA))
- {
- if (this->peek_token()->is_op(OPERATOR_COMMA))
- error_at(this->location(), "unexpected comma");
- if (this->advance_token()->is_op(follow))
- break;
- (this->*pfn)(varg);
- }
-}
-
-// ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
-
-void
-Parse::const_decl()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_CONST));
- this->advance_token();
- this->reset_iota();
-
- Type* last_type = NULL;
- Expression_list* last_expr_list = NULL;
-
- if (!this->peek_token()->is_op(OPERATOR_LPAREN))
- this->const_spec(&last_type, &last_expr_list);
- else
- {
- this->advance_token();
- while (!this->peek_token()->is_op(OPERATOR_RPAREN))
- {
- this->const_spec(&last_type, &last_expr_list);
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- this->advance_token();
- else if (!this->peek_token()->is_op(OPERATOR_RPAREN))
- {
- error_at(this->location(), "expected %<;%> or %<)%> or newline");
- if (!this->skip_past_error(OPERATOR_RPAREN))
- return;
- }
- }
- this->advance_token();
- }
-
- if (last_expr_list != NULL)
- delete last_expr_list;
-}
-
-// ConstSpec = IdentifierList [ [ CompleteType ] "=" ExpressionList ] .
-
-void
-Parse::const_spec(Type** last_type, Expression_list** last_expr_list)
-{
- Typed_identifier_list til;
- this->identifier_list(&til);
-
- Type* type = NULL;
- if (this->type_may_start_here())
- {
- type = this->type();
- *last_type = NULL;
- *last_expr_list = NULL;
- }
-
- Expression_list *expr_list;
- if (!this->peek_token()->is_op(OPERATOR_EQ))
- {
- if (*last_expr_list == NULL)
- {
- error_at(this->location(), "expected %<=%>");
- return;
- }
- type = *last_type;
- expr_list = new Expression_list;
- for (Expression_list::const_iterator p = (*last_expr_list)->begin();
- p != (*last_expr_list)->end();
- ++p)
- expr_list->push_back((*p)->copy());
- }
- else
- {
- this->advance_token();
- expr_list = this->expression_list(NULL, false, true);
- *last_type = type;
- if (*last_expr_list != NULL)
- delete *last_expr_list;
- *last_expr_list = expr_list;
- }
-
- Expression_list::const_iterator pe = expr_list->begin();
- for (Typed_identifier_list::iterator pi = til.begin();
- pi != til.end();
- ++pi, ++pe)
- {
- if (pe == expr_list->end())
- {
- error_at(this->location(), "not enough initializers");
- return;
- }
- if (type != NULL)
- pi->set_type(type);
-
- if (!Gogo::is_sink_name(pi->name()))
- this->gogo_->add_constant(*pi, *pe, this->iota_value());
- }
- if (pe != expr_list->end())
- error_at(this->location(), "too many initializers");
-
- this->increment_iota();
-
- return;
-}
-
-// TypeDecl = "type" Decl<TypeSpec> .
-
-void
-Parse::type_decl()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_TYPE));
- this->advance_token();
- this->decl(&Parse::type_spec, NULL);
-}
-
-// TypeSpec = identifier Type .
-
-void
-Parse::type_spec(void*)
-{
- const Token* token = this->peek_token();
- if (!token->is_identifier())
- {
- error_at(this->location(), "expected identifier");
- return;
- }
- std::string name = token->identifier();
- bool is_exported = token->is_identifier_exported();
- Location location = token->location();
- token = this->advance_token();
-
- // The scope of the type name starts at the point where the
- // identifier appears in the source code. We implement this by
- // declaring the type before we read the type definition.
- Named_object* named_type = NULL;
- if (name != "_")
- {
- name = this->gogo_->pack_hidden_name(name, is_exported);
- named_type = this->gogo_->declare_type(name, location);
- }
-
- Type* type;
- if (!this->peek_token()->is_op(OPERATOR_SEMICOLON))
- type = this->type();
- else
- {
- error_at(this->location(),
- "unexpected semicolon or newline in type declaration");
- type = Type::make_error_type();
- this->advance_token();
- }
-
- if (type->is_error_type())
- {
- this->gogo_->mark_locals_used();
- while (!this->peek_token()->is_op(OPERATOR_SEMICOLON)
- && !this->peek_token()->is_eof())
- this->advance_token();
- }
-
- if (name != "_")
- {
- if (named_type->is_type_declaration())
- {
- Type* ftype = type->forwarded();
- if (ftype->forward_declaration_type() != NULL
- && (ftype->forward_declaration_type()->named_object()
- == named_type))
- {
- error_at(location, "invalid recursive type");
- type = Type::make_error_type();
- }
-
- this->gogo_->define_type(named_type,
- Type::make_named_type(named_type, type,
- location));
- go_assert(named_type->package() == NULL);
- }
- else
- {
- // This will probably give a redefinition error.
- this->gogo_->add_type(name, type, location);
- }
- }
-}
-
-// VarDecl = "var" Decl<VarSpec> .
-
-void
-Parse::var_decl()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_VAR));
- this->advance_token();
- this->decl(&Parse::var_spec, NULL);
-}
-
-// VarSpec = IdentifierList
-// ( CompleteType [ "=" ExpressionList ] | "=" ExpressionList ) .
-
-void
-Parse::var_spec(void*)
-{
- // Get the variable names.
- Typed_identifier_list til;
- this->identifier_list(&til);
-
- Location location = this->location();
-
- Type* type = NULL;
- Expression_list* init = NULL;
- if (!this->peek_token()->is_op(OPERATOR_EQ))
- {
- type = this->type();
- if (type->is_error_type())
- {
- this->gogo_->mark_locals_used();
- while (!this->peek_token()->is_op(OPERATOR_EQ)
- && !this->peek_token()->is_op(OPERATOR_SEMICOLON)
- && !this->peek_token()->is_eof())
- this->advance_token();
- }
- if (this->peek_token()->is_op(OPERATOR_EQ))
- {
- this->advance_token();
- init = this->expression_list(NULL, false, true);
- }
- }
- else
- {
- this->advance_token();
- init = this->expression_list(NULL, false, true);
- }
-
- this->init_vars(&til, type, init, false, location);
-
- if (init != NULL)
- delete init;
-}
-
-// Create variables. TIL is a list of variable names. If TYPE is not
-// NULL, it is the type of all the variables. If INIT is not NULL, it
-// is an initializer list for the variables.
-
-void
-Parse::init_vars(const Typed_identifier_list* til, Type* type,
- Expression_list* init, bool is_coloneq,
- Location location)
-{
- // Check for an initialization which can yield multiple values.
- if (init != NULL && init->size() == 1 && til->size() > 1)
- {
- if (this->init_vars_from_call(til, type, *init->begin(), is_coloneq,
- location))
- return;
- if (this->init_vars_from_map(til, type, *init->begin(), is_coloneq,
- location))
- return;
- if (this->init_vars_from_receive(til, type, *init->begin(), is_coloneq,
- location))
- return;
- if (this->init_vars_from_type_guard(til, type, *init->begin(),
- is_coloneq, location))
- return;
- }
-
- if (init != NULL && init->size() != til->size())
- {
- if (init->empty() || !init->front()->is_error_expression())
- error_at(location, "wrong number of initializations");
- init = NULL;
- if (type == NULL)
- type = Type::make_error_type();
- }
-
- // Note that INIT was already parsed with the old name bindings, so
- // we don't have to worry that it will accidentally refer to the
- // newly declared variables. But we do have to worry about a mix of
- // newly declared variables and old variables if the old variables
- // appear in the initializations.
-
- Expression_list::const_iterator pexpr;
- if (init != NULL)
- pexpr = init->begin();
- bool any_new = false;
- Expression_list* vars = new Expression_list();
- Expression_list* vals = new Expression_list();
- for (Typed_identifier_list::const_iterator p = til->begin();
- p != til->end();
- ++p)
- {
- if (init != NULL)
- go_assert(pexpr != init->end());
- this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq,
- false, &any_new, vars, vals);
- if (init != NULL)
- ++pexpr;
- }
- if (init != NULL)
- go_assert(pexpr == init->end());
- if (is_coloneq && !any_new)
- error_at(location, "variables redeclared but no variable is new");
- this->finish_init_vars(vars, vals, location);
-}
-
-// See if we need to initialize a list of variables from a function
-// call. This returns true if we have set up the variables and the
-// initialization.
-
-bool
-Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
- Expression* expr, bool is_coloneq,
- Location location)
-{
- Call_expression* call = expr->call_expression();
- if (call == NULL)
- return false;
-
- // This is a function call. We can't check here whether it returns
- // the right number of values, but it might. Declare the variables,
- // and then assign the results of the call to them.
-
- Named_object* first_var = NULL;
- unsigned int index = 0;
- bool any_new = false;
- Expression_list* ivars = new Expression_list();
- Expression_list* ivals = new Expression_list();
- for (Typed_identifier_list::const_iterator pv = vars->begin();
- pv != vars->end();
- ++pv, ++index)
- {
- Expression* init = Expression::make_call_result(call, index);
- Named_object* no = this->init_var(*pv, type, init, is_coloneq, false,
- &any_new, ivars, ivals);
-
- if (this->gogo_->in_global_scope() && no->is_variable())
- {
- if (first_var == NULL)
- first_var = no;
- else
- {
- // The subsequent vars have an implicit dependency on
- // the first one, so that everything gets initialized in
- // the right order and so that we detect cycles
- // correctly.
- this->gogo_->record_var_depends_on(no->var_value(), first_var);
- }
- }
- }
-
- if (is_coloneq && !any_new)
- error_at(location, "variables redeclared but no variable is new");
-
- this->finish_init_vars(ivars, ivals, location);
-
- return true;
-}
-
-// See if we need to initialize a pair of values from a map index
-// expression. This returns true if we have set up the variables and
-// the initialization.
-
-bool
-Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
- Expression* expr, bool is_coloneq,
- Location location)
-{
- Index_expression* index = expr->index_expression();
- if (index == NULL)
- return false;
- if (vars->size() != 2)
- return false;
-
- // This is an index which is being assigned to two variables. It
- // must be a map index. Declare the variables, and then assign the
- // results of the map index.
- bool any_new = false;
- Typed_identifier_list::const_iterator p = vars->begin();
- Expression* init = type == NULL ? index : NULL;
- Named_object* val_no = this->init_var(*p, type, init, is_coloneq,
- type == NULL, &any_new, NULL, NULL);
- if (type == NULL && any_new && val_no->is_variable())
- val_no->var_value()->set_type_from_init_tuple();
- Expression* val_var = Expression::make_var_reference(val_no, location);
-
- ++p;
- Type* var_type = type;
- if (var_type == NULL)
- var_type = Type::lookup_bool_type();
- Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
- &any_new, NULL, NULL);
- Expression* present_var = Expression::make_var_reference(no, location);
-
- if (is_coloneq && !any_new)
- error_at(location, "variables redeclared but no variable is new");
-
- Statement* s = Statement::make_tuple_map_assignment(val_var, present_var,
- index, location);
-
- if (!this->gogo_->in_global_scope())
- this->gogo_->add_statement(s);
- else if (!val_no->is_sink())
- {
- if (val_no->is_variable())
- val_no->var_value()->add_preinit_statement(this->gogo_, s);
- }
- else if (!no->is_sink())
- {
- if (no->is_variable())
- no->var_value()->add_preinit_statement(this->gogo_, s);
- }
- else
- {
- // Execute the map index expression just so that we can fail if
- // the map is nil.
- Named_object* dummy = this->create_dummy_global(Type::lookup_bool_type(),
- NULL, location);
- dummy->var_value()->add_preinit_statement(this->gogo_, s);
- }
-
- return true;
-}
-
-// See if we need to initialize a pair of values from a receive
-// expression. This returns true if we have set up the variables and
-// the initialization.
-
-bool
-Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
- Expression* expr, bool is_coloneq,
- Location location)
-{
- Receive_expression* receive = expr->receive_expression();
- if (receive == NULL)
- return false;
- if (vars->size() != 2)
- return false;
-
- // This is a receive expression which is being assigned to two
- // variables. Declare the variables, and then assign the results of
- // the receive.
- bool any_new = false;
- Typed_identifier_list::const_iterator p = vars->begin();
- Expression* init = type == NULL ? receive : NULL;
- Named_object* val_no = this->init_var(*p, type, init, is_coloneq,
- type == NULL, &any_new, NULL, NULL);
- if (type == NULL && any_new && val_no->is_variable())
- val_no->var_value()->set_type_from_init_tuple();
- Expression* val_var = Expression::make_var_reference(val_no, location);
-
- ++p;
- Type* var_type = type;
- if (var_type == NULL)
- var_type = Type::lookup_bool_type();
- Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
- &any_new, NULL, NULL);
- Expression* received_var = Expression::make_var_reference(no, location);
-
- if (is_coloneq && !any_new)
- error_at(location, "variables redeclared but no variable is new");
-
- Statement* s = Statement::make_tuple_receive_assignment(val_var,
- received_var,
- receive->channel(),
- location);
-
- if (!this->gogo_->in_global_scope())
- this->gogo_->add_statement(s);
- else if (!val_no->is_sink())
- {
- if (val_no->is_variable())
- val_no->var_value()->add_preinit_statement(this->gogo_, s);
- }
- else if (!no->is_sink())
- {
- if (no->is_variable())
- no->var_value()->add_preinit_statement(this->gogo_, s);
- }
- else
- {
- Named_object* dummy = this->create_dummy_global(Type::lookup_bool_type(),
- NULL, location);
- dummy->var_value()->add_preinit_statement(this->gogo_, s);
- }
-
- return true;
-}
-
-// See if we need to initialize a pair of values from a type guard
-// expression. This returns true if we have set up the variables and
-// the initialization.
-
-bool
-Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
- Type* type, Expression* expr,
- bool is_coloneq, Location location)
-{
- Type_guard_expression* type_guard = expr->type_guard_expression();
- if (type_guard == NULL)
- return false;
- if (vars->size() != 2)
- return false;
-
- // This is a type guard expression which is being assigned to two
- // variables. Declare the variables, and then assign the results of
- // the type guard.
- bool any_new = false;
- Typed_identifier_list::const_iterator p = vars->begin();
- Type* var_type = type;
- if (var_type == NULL)
- var_type = type_guard->type();
- Named_object* val_no = this->init_var(*p, var_type, NULL, is_coloneq, false,
- &any_new, NULL, NULL);
- Expression* val_var = Expression::make_var_reference(val_no, location);
-
- ++p;
- var_type = type;
- if (var_type == NULL)
- var_type = Type::lookup_bool_type();
- Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
- &any_new, NULL, NULL);
- Expression* ok_var = Expression::make_var_reference(no, location);
-
- Expression* texpr = type_guard->expr();
- Type* t = type_guard->type();
- Statement* s = Statement::make_tuple_type_guard_assignment(val_var, ok_var,
- texpr, t,
- location);
-
- if (is_coloneq && !any_new)
- error_at(location, "variables redeclared but no variable is new");
-
- if (!this->gogo_->in_global_scope())
- this->gogo_->add_statement(s);
- else if (!val_no->is_sink())
- {
- if (val_no->is_variable())
- val_no->var_value()->add_preinit_statement(this->gogo_, s);
- }
- else if (!no->is_sink())
- {
- if (no->is_variable())
- no->var_value()->add_preinit_statement(this->gogo_, s);
- }
- else
- {
- Named_object* dummy = this->create_dummy_global(type, NULL, location);
- dummy->var_value()->add_preinit_statement(this->gogo_, s);
- }
-
- return true;
-}
-
-// Create a single variable. If IS_COLONEQ is true, we permit
-// redeclarations in the same block, and we set *IS_NEW when we find a
-// new variable which is not a redeclaration.
-
-Named_object*
-Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
- bool is_coloneq, bool type_from_init, bool* is_new,
- Expression_list* vars, Expression_list* vals)
-{
- Location location = tid.location();
-
- if (Gogo::is_sink_name(tid.name()))
- {
- if (!type_from_init && init != NULL)
- {
- if (this->gogo_->in_global_scope())
- return this->create_dummy_global(type, init, location);
- else if (type == NULL)
- this->gogo_->add_statement(Statement::make_statement(init, true));
- else
- {
- // With both a type and an initializer, create a dummy
- // variable so that we will check whether the
- // initializer can be assigned to the type.
- Variable* var = new Variable(type, init, false, false, false,
- location);
- var->set_is_used();
- static int count;
- char buf[30];
- snprintf(buf, sizeof buf, "sink$%d", count);
- ++count;
- return this->gogo_->add_variable(buf, var);
- }
- }
- if (type != NULL)
- this->gogo_->add_type_to_verify(type);
- return this->gogo_->add_sink();
- }
-
- if (is_coloneq)
- {
- Named_object* no = this->gogo_->lookup_in_block(tid.name());
- if (no != NULL
- && (no->is_variable() || no->is_result_variable()))
- {
- // INIT may be NULL even when IS_COLONEQ is true for cases
- // like v, ok := x.(int).
- if (!type_from_init && init != NULL)
- {
- go_assert(vars != NULL && vals != NULL);
- vars->push_back(Expression::make_var_reference(no, location));
- vals->push_back(init);
- }
- return no;
- }
- }
- *is_new = true;
- Variable* var = new Variable(type, init, this->gogo_->in_global_scope(),
- false, false, location);
- Named_object* no = this->gogo_->add_variable(tid.name(), var);
- if (!no->is_variable())
- {
- // The name is already defined, so we just gave an error.
- return this->gogo_->add_sink();
- }
- return no;
-}
-
-// Create a dummy global variable to force an initializer to be run in
-// the right place. This is used when a sink variable is initialized
-// at global scope.
-
-Named_object*
-Parse::create_dummy_global(Type* type, Expression* init,
- Location location)
-{
- if (type == NULL && init == NULL)
- type = Type::lookup_bool_type();
- Variable* var = new Variable(type, init, true, false, false, location);
- static int count;
- char buf[30];
- snprintf(buf, sizeof buf, "_.%d", count);
- ++count;
- return this->gogo_->add_variable(buf, var);
-}
-
-// Finish the variable initialization by executing any assignments to
-// existing variables when using :=. These must be done as a tuple
-// assignment in case of something like n, a, b := 1, b, a.
-
-void
-Parse::finish_init_vars(Expression_list* vars, Expression_list* vals,
- Location location)
-{
- if (vars->empty())
- {
- delete vars;
- delete vals;
- }
- else if (vars->size() == 1)
- {
- go_assert(!this->gogo_->in_global_scope());
- this->gogo_->add_statement(Statement::make_assignment(vars->front(),
- vals->front(),
- location));
- delete vars;
- delete vals;
- }
- else
- {
- go_assert(!this->gogo_->in_global_scope());
- this->gogo_->add_statement(Statement::make_tuple_assignment(vars, vals,
- location));
- }
-}
-
-// SimpleVarDecl = identifier ":=" Expression .
-
-// We've already seen the identifier.
-
-// FIXME: We also have to implement
-// IdentifierList ":=" ExpressionList
-// In order to support both "a, b := 1, 0" and "a, b = 1, 0" we accept
-// tuple assignments here as well.
-
-// If MAY_BE_COMPOSITE_LIT is true, the expression on the right hand
-// side may be a composite literal.
-
-// If P_RANGE_CLAUSE is not NULL, then this will recognize a
-// RangeClause.
-
-// If P_TYPE_SWITCH is not NULL, this will recognize a type switch
-// guard (var := expr.("type") using the literal keyword "type").
-
-void
-Parse::simple_var_decl_or_assignment(const std::string& name,
- Location location,
- bool may_be_composite_lit,
- Range_clause* p_range_clause,
- Type_switch* p_type_switch)
-{
- Typed_identifier_list til;
- til.push_back(Typed_identifier(name, NULL, location));
-
- // We've seen one identifier. If we see a comma now, this could be
- // "a, *p = 1, 2".
- if (this->peek_token()->is_op(OPERATOR_COMMA))
- {
- go_assert(p_type_switch == NULL);
- while (true)
- {
- const Token* token = this->advance_token();
- if (!token->is_identifier())
- break;
-
- std::string id = token->identifier();
- bool is_id_exported = token->is_identifier_exported();
- Location id_location = token->location();
-
- token = this->advance_token();
- if (!token->is_op(OPERATOR_COMMA))
- {
- if (token->is_op(OPERATOR_COLONEQ))
- {
- id = this->gogo_->pack_hidden_name(id, is_id_exported);
- til.push_back(Typed_identifier(id, NULL, location));
- }
- else
- this->unget_token(Token::make_identifier_token(id,
- is_id_exported,
- id_location));
- break;
- }
-
- id = this->gogo_->pack_hidden_name(id, is_id_exported);
- til.push_back(Typed_identifier(id, NULL, location));
- }
-
- // We have a comma separated list of identifiers in TIL. If the
- // next token is COLONEQ, then this is a simple var decl, and we
- // have the complete list of identifiers. If the next token is
- // not COLONEQ, then the only valid parse is a tuple assignment.
- // The list of identifiers we have so far is really a list of
- // expressions. There are more expressions following.
-
- if (!this->peek_token()->is_op(OPERATOR_COLONEQ))
- {
- Expression_list* exprs = new Expression_list;
- for (Typed_identifier_list::const_iterator p = til.begin();
- p != til.end();
- ++p)
- exprs->push_back(this->id_to_expression(p->name(),
- p->location()));
-
- Expression_list* more_exprs =
- this->expression_list(NULL, true, may_be_composite_lit);
- for (Expression_list::const_iterator p = more_exprs->begin();
- p != more_exprs->end();
- ++p)
- exprs->push_back(*p);
- delete more_exprs;
-
- this->tuple_assignment(exprs, may_be_composite_lit, p_range_clause);
- return;
- }
- }
-
- go_assert(this->peek_token()->is_op(OPERATOR_COLONEQ));
- const Token* token = this->advance_token();
-
- if (p_range_clause != NULL && token->is_keyword(KEYWORD_RANGE))
- {
- this->range_clause_decl(&til, p_range_clause);
- return;
- }
-
- Expression_list* init;
- if (p_type_switch == NULL)
- init = this->expression_list(NULL, false, may_be_composite_lit);
- else
- {
- bool is_type_switch = false;
- Expression* expr = this->expression(PRECEDENCE_NORMAL, false,
- may_be_composite_lit,
- &is_type_switch, NULL);
- if (is_type_switch)
- {
- p_type_switch->found = true;
- p_type_switch->name = name;
- p_type_switch->location = location;
- p_type_switch->expr = expr;
- return;
- }
-
- if (!this->peek_token()->is_op(OPERATOR_COMMA))
- {
- init = new Expression_list();
- init->push_back(expr);
- }
- else
- {
- this->advance_token();
- init = this->expression_list(expr, false, may_be_composite_lit);
- }
- }
-
- this->init_vars(&til, NULL, init, true, location);
-}
-
-// FunctionDecl = "func" identifier Signature [ Block ] .
-// MethodDecl = "func" Receiver identifier Signature [ Block ] .
-
-// Deprecated gcc extension:
-// FunctionDecl = "func" identifier Signature
-// __asm__ "(" string_lit ")" .
-// This extension means a function whose real name is the identifier
-// inside the asm. This extension will be removed at some future
-// date. It has been replaced with //extern comments.
-
-// SAW_NOINTERFACE is true if we saw a magic //go:nointerface comment,
-// which means that we omit the method from the type descriptor.
-
-void
-Parse::function_decl(bool saw_nointerface)
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
- Location location = this->location();
- std::string extern_name = this->lex_->extern_name();
- const Token* token = this->advance_token();
-
- Typed_identifier* rec = NULL;
- if (token->is_op(OPERATOR_LPAREN))
- {
- rec = this->receiver();
- token = this->peek_token();
- }
- else if (saw_nointerface)
- {
- warning_at(location, 0,
- "ignoring magic //go:nointerface comment before non-method");
- saw_nointerface = false;
- }
-
- if (!token->is_identifier())
- {
- error_at(this->location(), "expected function name");
- return;
- }
-
- std::string name =
- this->gogo_->pack_hidden_name(token->identifier(),
- token->is_identifier_exported());
-
- this->advance_token();
-
- Function_type* fntype = this->signature(rec, this->location());
-
- Named_object* named_object = NULL;
-
- if (this->peek_token()->is_keyword(KEYWORD_ASM))
- {
- if (!this->advance_token()->is_op(OPERATOR_LPAREN))
- {
- error_at(this->location(), "expected %<(%>");
- return;
- }
- token = this->advance_token();
- if (!token->is_string())
- {
- error_at(this->location(), "expected string");
- return;
- }
- std::string asm_name = token->string_value();
- if (!this->advance_token()->is_op(OPERATOR_RPAREN))
- {
- error_at(this->location(), "expected %<)%>");
- return;
- }
- this->advance_token();
- if (!Gogo::is_sink_name(name))
- {
- named_object = this->gogo_->declare_function(name, fntype, location);
- if (named_object->is_function_declaration())
- named_object->func_declaration_value()->set_asm_name(asm_name);
- }
- }
-
- // Check for the easy error of a newline before the opening brace.
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- {
- Location semi_loc = this->location();
- if (this->advance_token()->is_op(OPERATOR_LCURLY))
- error_at(this->location(),
- "unexpected semicolon or newline before %<{%>");
- else
- this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,
- semi_loc));
- }
-
- if (!this->peek_token()->is_op(OPERATOR_LCURLY))
- {
- if (named_object == NULL && !Gogo::is_sink_name(name))
- {
- if (fntype == NULL)
- this->gogo_->add_erroneous_name(name);
- else
- {
- named_object = this->gogo_->declare_function(name, fntype,
- location);
- if (!extern_name.empty()
- && named_object->is_function_declaration())
- {
- Function_declaration* fd =
- named_object->func_declaration_value();
- fd->set_asm_name(extern_name);
- }
- }
- }
-
- if (saw_nointerface)
- warning_at(location, 0,
- ("ignoring magic //go:nointerface comment "
- "before declaration"));
- }
- else
- {
- bool hold_is_erroneous_function = this->is_erroneous_function_;
- if (fntype == NULL)
- {
- fntype = Type::make_function_type(NULL, NULL, NULL, location);
- this->is_erroneous_function_ = true;
- if (!Gogo::is_sink_name(name))
- this->gogo_->add_erroneous_name(name);
- name = this->gogo_->pack_hidden_name("_", false);
- }
- named_object = this->gogo_->start_function(name, fntype, true, location);
- Location end_loc = this->block();
- this->gogo_->finish_function(end_loc);
- if (saw_nointerface
- && !this->is_erroneous_function_
- && named_object->is_function())
- named_object->func_value()->set_nointerface();
- this->is_erroneous_function_ = hold_is_erroneous_function;
- }
-}
-
-// Receiver = "(" [ identifier ] [ "*" ] BaseTypeName ")" .
-// BaseTypeName = identifier .
-
-Typed_identifier*
-Parse::receiver()
-{
- go_assert(this->peek_token()->is_op(OPERATOR_LPAREN));
-
- std::string name;
- const Token* token = this->advance_token();
- Location location = token->location();
- if (!token->is_op(OPERATOR_MULT))
- {
- if (!token->is_identifier())
- {
- error_at(this->location(), "method has no receiver");
- this->gogo_->mark_locals_used();
- while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN))
- token = this->advance_token();
- if (!token->is_eof())
- this->advance_token();
- return NULL;
- }
- name = token->identifier();
- bool is_exported = token->is_identifier_exported();
- token = this->advance_token();
- if (!token->is_op(OPERATOR_DOT) && !token->is_op(OPERATOR_RPAREN))
- {
- // An identifier followed by something other than a dot or a
- // right parenthesis must be a receiver name followed by a
- // type.
- name = this->gogo_->pack_hidden_name(name, is_exported);
- }
- else
- {
- // This must be a type name.
- this->unget_token(Token::make_identifier_token(name, is_exported,
- location));
- token = this->peek_token();
- name.clear();
- }
- }
-
- // Here the receiver name is in NAME (it is empty if the receiver is
- // unnamed) and TOKEN is the first token in the type.
-
- bool is_pointer = false;
- if (token->is_op(OPERATOR_MULT))
- {
- is_pointer = true;
- token = this->advance_token();
- }
-
- if (!token->is_identifier())
- {
- error_at(this->location(), "expected receiver name or type");
- this->gogo_->mark_locals_used();
- int c = token->is_op(OPERATOR_LPAREN) ? 1 : 0;
- while (!token->is_eof())
- {
- token = this->advance_token();
- if (token->is_op(OPERATOR_LPAREN))
- ++c;
- else if (token->is_op(OPERATOR_RPAREN))
- {
- if (c == 0)
- break;
- --c;
- }
- }
- if (!token->is_eof())
- this->advance_token();
- return NULL;
- }
-
- Type* type = this->type_name(true);
-
- if (is_pointer && !type->is_error_type())
- type = Type::make_pointer_type(type);
-
- if (this->peek_token()->is_op(OPERATOR_RPAREN))
- this->advance_token();
- else
- {
- if (this->peek_token()->is_op(OPERATOR_COMMA))
- error_at(this->location(), "method has multiple receivers");
- else
- error_at(this->location(), "expected %<)%>");
- this->gogo_->mark_locals_used();
- while (!token->is_eof() && !token->is_op(OPERATOR_RPAREN))
- token = this->advance_token();
- if (!token->is_eof())
- this->advance_token();
- return NULL;
- }
-
- return new Typed_identifier(name, type, location);
-}
-
-// Operand = Literal | QualifiedIdent | MethodExpr | "(" Expression ")" .
-// Literal = BasicLit | CompositeLit | FunctionLit .
-// BasicLit = int_lit | float_lit | imaginary_lit | char_lit | string_lit .
-
-// If MAY_BE_SINK is true, this operand may be "_".
-
-// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true
-// if the entire expression is in parentheses.
-
-Expression*
-Parse::operand(bool may_be_sink, bool* is_parenthesized)
-{
- const Token* token = this->peek_token();
- Expression* ret;
- switch (token->classification())
- {
- case Token::TOKEN_IDENTIFIER:
- {
- Location location = token->location();
- std::string id = token->identifier();
- bool is_exported = token->is_identifier_exported();
- std::string packed = this->gogo_->pack_hidden_name(id, is_exported);
-
- Named_object* in_function;
- Named_object* named_object = this->gogo_->lookup(packed, &in_function);
-
- Package* package = NULL;
- if (named_object != NULL && named_object->is_package())
- {
- if (!this->advance_token()->is_op(OPERATOR_DOT)
- || !this->advance_token()->is_identifier())
- {
- error_at(location, "unexpected reference to package");
- return Expression::make_error(location);
- }
- package = named_object->package_value();
- package->set_used();
- id = this->peek_token()->identifier();
- is_exported = this->peek_token()->is_identifier_exported();
- packed = this->gogo_->pack_hidden_name(id, is_exported);
- named_object = package->lookup(packed);
- location = this->location();
- go_assert(in_function == NULL);
- }
-
- this->advance_token();
-
- if (named_object != NULL
- && named_object->is_type()
- && !named_object->type_value()->is_visible())
- {
- go_assert(package != NULL);
- error_at(location, "invalid reference to hidden type %<%s.%s%>",
- Gogo::message_name(package->package_name()).c_str(),
- Gogo::message_name(id).c_str());
- return Expression::make_error(location);
- }
-
-
- if (named_object == NULL)
- {
- if (package != NULL)
- {
- std::string n1 = Gogo::message_name(package->package_name());
- std::string n2 = Gogo::message_name(id);
- if (!is_exported)
- error_at(location,
- ("invalid reference to unexported identifier "
- "%<%s.%s%>"),
- n1.c_str(), n2.c_str());
- else
- error_at(location,
- "reference to undefined identifier %<%s.%s%>",
- n1.c_str(), n2.c_str());
- return Expression::make_error(location);
- }
-
- named_object = this->gogo_->add_unknown_name(packed, location);
- }
-
- if (in_function != NULL
- && in_function != this->gogo_->current_function()
- && (named_object->is_variable()
- || named_object->is_result_variable()))
- return this->enclosing_var_reference(in_function, named_object,
- location);
-
- switch (named_object->classification())
- {
- case Named_object::NAMED_OBJECT_CONST:
- return Expression::make_const_reference(named_object, location);
- case Named_object::NAMED_OBJECT_TYPE:
- return Expression::make_type(named_object->type_value(), location);
- case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
- {
- Type* t = Type::make_forward_declaration(named_object);
- return Expression::make_type(t, location);
- }
- case Named_object::NAMED_OBJECT_VAR:
- case Named_object::NAMED_OBJECT_RESULT_VAR:
- this->mark_var_used(named_object);
- return Expression::make_var_reference(named_object, location);
- case Named_object::NAMED_OBJECT_SINK:
- if (may_be_sink)
- return Expression::make_sink(location);
- else
- {
- error_at(location, "cannot use _ as value");
- return Expression::make_error(location);
- }
- case Named_object::NAMED_OBJECT_FUNC:
- case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
- return Expression::make_func_reference(named_object, NULL,
- location);
- case Named_object::NAMED_OBJECT_UNKNOWN:
- {
- Unknown_expression* ue =
- Expression::make_unknown_reference(named_object, location);
- if (this->is_erroneous_function_)
- ue->set_no_error_message();
- return ue;
- }
- case Named_object::NAMED_OBJECT_ERRONEOUS:
- return Expression::make_error(location);
- default:
- go_unreachable();
- }
- }
- go_unreachable();
-
- case Token::TOKEN_STRING:
- ret = Expression::make_string(token->string_value(), token->location());
- this->advance_token();
- return ret;
-
- case Token::TOKEN_CHARACTER:
- ret = Expression::make_character(token->character_value(), NULL,
- token->location());
- this->advance_token();
- return ret;
-
- case Token::TOKEN_INTEGER:
- ret = Expression::make_integer(token->integer_value(), NULL,
- token->location());
- this->advance_token();
- return ret;
-
- case Token::TOKEN_FLOAT:
- ret = Expression::make_float(token->float_value(), NULL,
- token->location());
- this->advance_token();
- return ret;
-
- case Token::TOKEN_IMAGINARY:
- {
- mpfr_t zero;
- mpfr_init_set_ui(zero, 0, GMP_RNDN);
- ret = Expression::make_complex(&zero, token->imaginary_value(),
- NULL, token->location());
- mpfr_clear(zero);
- this->advance_token();
- return ret;
- }
-
- case Token::TOKEN_KEYWORD:
- switch (token->keyword())
- {
- case KEYWORD_FUNC:
- return this->function_lit();
- case KEYWORD_CHAN:
- case KEYWORD_INTERFACE:
- case KEYWORD_MAP:
- case KEYWORD_STRUCT:
- {
- Location location = token->location();
- return Expression::make_type(this->type(), location);
- }
- default:
- break;
- }
- break;
-
- case Token::TOKEN_OPERATOR:
- if (token->is_op(OPERATOR_LPAREN))
- {
- this->advance_token();
- ret = this->expression(PRECEDENCE_NORMAL, may_be_sink, true, NULL,
- NULL);
- if (!this->peek_token()->is_op(OPERATOR_RPAREN))
- error_at(this->location(), "missing %<)%>");
- else
- this->advance_token();
- if (is_parenthesized != NULL)
- *is_parenthesized = true;
- return ret;
- }
- else if (token->is_op(OPERATOR_LSQUARE))
- {
- // Here we call array_type directly, as this is the only
- // case where an ellipsis is permitted for an array type.
- Location location = token->location();
- return Expression::make_type(this->array_type(true), location);
- }
- break;
-
- default:
- break;
- }
-
- error_at(this->location(), "expected operand");
- return Expression::make_error(this->location());
-}
-
-// Handle a reference to a variable in an enclosing function. We add
-// it to a list of such variables. We return a reference to a field
-// in a struct which will be passed on the static chain when calling
-// the current function.
-
-Expression*
-Parse::enclosing_var_reference(Named_object* in_function, Named_object* var,
- Location location)
-{
- go_assert(var->is_variable() || var->is_result_variable());
-
- this->mark_var_used(var);
-
- Named_object* this_function = this->gogo_->current_function();
- Named_object* closure = this_function->func_value()->closure_var();
-
- Enclosing_var ev(var, in_function, this->enclosing_vars_.size());
- std::pair<Enclosing_vars::iterator, bool> ins =
- this->enclosing_vars_.insert(ev);
- if (ins.second)
- {
- // This is a variable we have not seen before. Add a new field
- // to the closure type.
- this_function->func_value()->add_closure_field(var, location);
- }
-
- Expression* closure_ref = Expression::make_var_reference(closure,
- location);
- closure_ref = Expression::make_unary(OPERATOR_MULT, closure_ref, location);
-
- // The closure structure holds pointers to the variables, so we need
- // to introduce an indirection.
- Expression* e = Expression::make_field_reference(closure_ref,
- ins.first->index(),
- location);
- e = Expression::make_unary(OPERATOR_MULT, e, location);
- return e;
-}
-
-// CompositeLit = LiteralType LiteralValue .
-// LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
-// SliceType | MapType | TypeName .
-// LiteralValue = "{" [ ElementList [ "," ] ] "}" .
-// ElementList = Element { "," Element } .
-// Element = [ Key ":" ] Value .
-// Key = FieldName | ElementIndex .
-// FieldName = identifier .
-// ElementIndex = Expression .
-// Value = Expression | LiteralValue .
-
-// We have already seen the type if there is one, and we are now
-// looking at the LiteralValue. The case "[" "..." "]" ElementType
-// will be seen here as an array type whose length is "nil". The
-// DEPTH parameter is non-zero if this is an embedded composite
-// literal and the type was omitted. It gives the number of steps up
-// to the type which was provided. E.g., in [][]int{{1}} it will be
-// 1. In [][][]int{{{1}}} it will be 2.
-
-Expression*
-Parse::composite_lit(Type* type, int depth, Location location)
-{
- go_assert(this->peek_token()->is_op(OPERATOR_LCURLY));
- this->advance_token();
-
- if (this->peek_token()->is_op(OPERATOR_RCURLY))
- {
- this->advance_token();
- return Expression::make_composite_literal(type, depth, false, NULL,
- location);
- }
-
- bool has_keys = false;
- Expression_list* vals = new Expression_list;
- while (true)
- {
- Expression* val;
- bool is_type_omitted = false;
-
- const Token* token = this->peek_token();
-
- if (token->is_identifier())
- {
- std::string identifier = token->identifier();
- bool is_exported = token->is_identifier_exported();
- Location location = token->location();
-
- if (this->advance_token()->is_op(OPERATOR_COLON))
- {
- // This may be a field name. We don't know for sure--it
- // could also be an expression for an array index. We
- // don't want to parse it as an expression because may
- // trigger various errors, e.g., if this identifier
- // happens to be the name of a package.
- Gogo* gogo = this->gogo_;
- val = this->id_to_expression(gogo->pack_hidden_name(identifier,
- is_exported),
- location);
- }
- else
- {
- this->unget_token(Token::make_identifier_token(identifier,
- is_exported,
- location));
- val = this->expression(PRECEDENCE_NORMAL, false, true, NULL,
- NULL);
- }
- }
- else if (!token->is_op(OPERATOR_LCURLY))
- val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
- else
- {
- // This must be a composite literal inside another composite
- // literal, with the type omitted for the inner one.
- val = this->composite_lit(type, depth + 1, token->location());
- is_type_omitted = true;
- }
-
- token = this->peek_token();
- if (!token->is_op(OPERATOR_COLON))
- {
- if (has_keys)
- vals->push_back(NULL);
- }
- else
- {
- if (is_type_omitted && !val->is_error_expression())
- {
- error_at(this->location(), "unexpected %<:%>");
- val = Expression::make_error(this->location());
- }
-
- this->advance_token();
-
- if (!has_keys && !vals->empty())
- {
- Expression_list* newvals = new Expression_list;
- for (Expression_list::const_iterator p = vals->begin();
- p != vals->end();
- ++p)
- {
- newvals->push_back(NULL);
- newvals->push_back(*p);
- }
- delete vals;
- vals = newvals;
- }
- has_keys = true;
-
- if (val->unknown_expression() != NULL)
- val->unknown_expression()->set_is_composite_literal_key();
-
- vals->push_back(val);
-
- if (!token->is_op(OPERATOR_LCURLY))
- val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
- else
- {
- // This must be a composite literal inside another
- // composite literal, with the type omitted for the
- // inner one.
- val = this->composite_lit(type, depth + 1, token->location());
- }
-
- token = this->peek_token();
- }
-
- vals->push_back(val);
-
- if (token->is_op(OPERATOR_COMMA))
- {
- if (this->advance_token()->is_op(OPERATOR_RCURLY))
- {
- this->advance_token();
- break;
- }
- }
- else if (token->is_op(OPERATOR_RCURLY))
- {
- this->advance_token();
- break;
- }
- else
- {
- if (token->is_op(OPERATOR_SEMICOLON))
- error_at(this->location(),
- "need trailing comma before newline in composite literal");
- else
- error_at(this->location(), "expected %<,%> or %<}%>");
-
- this->gogo_->mark_locals_used();
- int depth = 0;
- while (!token->is_eof()
- && (depth > 0 || !token->is_op(OPERATOR_RCURLY)))
- {
- if (token->is_op(OPERATOR_LCURLY))
- ++depth;
- else if (token->is_op(OPERATOR_RCURLY))
- --depth;
- token = this->advance_token();
- }
- if (token->is_op(OPERATOR_RCURLY))
- this->advance_token();
-
- return Expression::make_error(location);
- }
- }
-
- return Expression::make_composite_literal(type, depth, has_keys, vals,
- location);
-}
-
-// FunctionLit = "func" Signature Block .
-
-Expression*
-Parse::function_lit()
-{
- Location location = this->location();
- go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
- this->advance_token();
-
- Enclosing_vars hold_enclosing_vars;
- hold_enclosing_vars.swap(this->enclosing_vars_);
-
- Function_type* type = this->signature(NULL, location);
- bool fntype_is_error = false;
- if (type == NULL)
- {
- type = Type::make_function_type(NULL, NULL, NULL, location);
- fntype_is_error = true;
- }
-
- // For a function literal, the next token must be a '{'. If we
- // don't see that, then we may have a type expression.
- if (!this->peek_token()->is_op(OPERATOR_LCURLY))
- return Expression::make_type(type, location);
-
- bool hold_is_erroneous_function = this->is_erroneous_function_;
- if (fntype_is_error)
- this->is_erroneous_function_ = true;
-
- Bc_stack* hold_break_stack = this->break_stack_;
- Bc_stack* hold_continue_stack = this->continue_stack_;
- this->break_stack_ = NULL;
- this->continue_stack_ = NULL;
-
- Named_object* no = this->gogo_->start_function("", type, true, location);
-
- Location end_loc = this->block();
-
- this->gogo_->finish_function(end_loc);
-
- if (this->break_stack_ != NULL)
- delete this->break_stack_;
- if (this->continue_stack_ != NULL)
- delete this->continue_stack_;
- this->break_stack_ = hold_break_stack;
- this->continue_stack_ = hold_continue_stack;
-
- this->is_erroneous_function_ = hold_is_erroneous_function;
-
- hold_enclosing_vars.swap(this->enclosing_vars_);
-
- Expression* closure = this->create_closure(no, &hold_enclosing_vars,
- location);
-
- return Expression::make_func_reference(no, closure, location);
-}
-
-// Create a closure for the nested function FUNCTION. This is based
-// on ENCLOSING_VARS, which is a list of all variables defined in
-// enclosing functions and referenced from FUNCTION. A closure is the
-// address of a struct which contains the addresses of all the
-// referenced variables. This returns NULL if no closure is required.
-
-Expression*
-Parse::create_closure(Named_object* function, Enclosing_vars* enclosing_vars,
- Location location)
-{
- if (enclosing_vars->empty())
- return NULL;
-
- // Get the variables in order by their field index.
-
- size_t enclosing_var_count = enclosing_vars->size();
- std::vector<Enclosing_var> ev(enclosing_var_count);
- for (Enclosing_vars::const_iterator p = enclosing_vars->begin();
- p != enclosing_vars->end();
- ++p)
- ev[p->index()] = *p;
-
- // Build an initializer for a composite literal of the closure's
- // type.
-
- Named_object* enclosing_function = this->gogo_->current_function();
- Expression_list* initializer = new Expression_list;
- for (size_t i = 0; i < enclosing_var_count; ++i)
- {
- go_assert(ev[i].index() == i);
- Named_object* var = ev[i].var();
- Expression* ref;
- if (ev[i].in_function() == enclosing_function)
- ref = Expression::make_var_reference(var, location);
- else
- ref = this->enclosing_var_reference(ev[i].in_function(), var,
- location);
- Expression* refaddr = Expression::make_unary(OPERATOR_AND, ref,
- location);
- initializer->push_back(refaddr);
- }
-
- Named_object* closure_var = function->func_value()->closure_var();
- Struct_type* st = closure_var->var_value()->type()->deref()->struct_type();
- Expression* cv = Expression::make_struct_composite_literal(st, initializer,
- location);
- return Expression::make_heap_composite(cv, location);
-}
-
-// PrimaryExpr = Operand { Selector | Index | Slice | TypeGuard | Call } .
-
-// If MAY_BE_SINK is true, this expression may be "_".
-
-// If MAY_BE_COMPOSITE_LIT is true, this expression may be a composite
-// literal.
-
-// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
-// guard (var := expr.("type") using the literal keyword "type").
-
-// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true
-// if the entire expression is in parentheses.
-
-Expression*
-Parse::primary_expr(bool may_be_sink, bool may_be_composite_lit,
- bool* is_type_switch, bool* is_parenthesized)
-{
- Location start_loc = this->location();
- bool operand_is_parenthesized = false;
- bool whole_is_parenthesized = false;
-
- Expression* ret = this->operand(may_be_sink, &operand_is_parenthesized);
-
- whole_is_parenthesized = operand_is_parenthesized;
-
- // An unknown name followed by a curly brace must be a composite
- // literal, and the unknown name must be a type.
- if (may_be_composite_lit
- && !operand_is_parenthesized
- && ret->unknown_expression() != NULL
- && this->peek_token()->is_op(OPERATOR_LCURLY))
- {
- Named_object* no = ret->unknown_expression()->named_object();
- Type* type = Type::make_forward_declaration(no);
- ret = Expression::make_type(type, ret->location());
- }
-
- // We handle composite literals and type casts here, as it is the
- // easiest way to handle types which are in parentheses, as in
- // "((uint))(1)".
- if (ret->is_type_expression())
- {
- if (this->peek_token()->is_op(OPERATOR_LCURLY))
- {
- whole_is_parenthesized = false;
- if (!may_be_composite_lit)
- {
- Type* t = ret->type();
- if (t->named_type() != NULL
- || t->forward_declaration_type() != NULL)
- error_at(start_loc,
- _("parentheses required around this composite literal "
- "to avoid parsing ambiguity"));
- }
- else if (operand_is_parenthesized)
- error_at(start_loc,
- "cannot parenthesize type in composite literal");
- ret = this->composite_lit(ret->type(), 0, ret->location());
- }
- else if (this->peek_token()->is_op(OPERATOR_LPAREN))
- {
- whole_is_parenthesized = false;
- Location loc = this->location();
- this->advance_token();
- Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true,
- NULL, NULL);
- if (this->peek_token()->is_op(OPERATOR_COMMA))
- this->advance_token();
- if (this->peek_token()->is_op(OPERATOR_ELLIPSIS))
- {
- error_at(this->location(),
- "invalid use of %<...%> in type conversion");
- this->advance_token();
- }
- if (!this->peek_token()->is_op(OPERATOR_RPAREN))
- error_at(this->location(), "expected %<)%>");
- else
- this->advance_token();
- if (expr->is_error_expression())
- ret = expr;
- else
- {
- Type* t = ret->type();
- if (t->classification() == Type::TYPE_ARRAY
- && t->array_type()->length() != NULL
- && t->array_type()->length()->is_nil_expression())
- {
- error_at(ret->location(),
- "invalid use of %<...%> in type conversion");
- ret = Expression::make_error(loc);
- }
- else
- ret = Expression::make_cast(t, expr, loc);
- }
- }
- }
-
- while (true)
- {
- const Token* token = this->peek_token();
- if (token->is_op(OPERATOR_LPAREN))
- {
- whole_is_parenthesized = false;
- ret = this->call(this->verify_not_sink(ret));
- }
- else if (token->is_op(OPERATOR_DOT))
- {
- whole_is_parenthesized = false;
- ret = this->selector(this->verify_not_sink(ret), is_type_switch);
- if (is_type_switch != NULL && *is_type_switch)
- break;
- }
- else if (token->is_op(OPERATOR_LSQUARE))
- {
- whole_is_parenthesized = false;
- ret = this->index(this->verify_not_sink(ret));
- }
- else
- break;
- }
-
- if (whole_is_parenthesized && is_parenthesized != NULL)
- *is_parenthesized = true;
-
- return ret;
-}
-
-// Selector = "." identifier .
-// TypeGuard = "." "(" QualifiedIdent ")" .
-
-// Note that Operand can expand to QualifiedIdent, which contains a
-// ".". That is handled directly in operand when it sees a package
-// name.
-
-// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
-// guard (var := expr.("type") using the literal keyword "type").
-
-Expression*
-Parse::selector(Expression* left, bool* is_type_switch)
-{
- go_assert(this->peek_token()->is_op(OPERATOR_DOT));
- Location location = this->location();
-
- const Token* token = this->advance_token();
- if (token->is_identifier())
- {
- // This could be a field in a struct, or a method in an
- // interface, or a method associated with a type. We can't know
- // which until we have seen all the types.
- std::string name =
- this->gogo_->pack_hidden_name(token->identifier(),
- token->is_identifier_exported());
- if (token->identifier() == "_")
- {
- error_at(this->location(), "invalid use of %<_%>");
- name = this->gogo_->pack_hidden_name("blank", false);
- }
- this->advance_token();
- return Expression::make_selector(left, name, location);
- }
- else if (token->is_op(OPERATOR_LPAREN))
- {
- this->advance_token();
- Type* type = NULL;
- if (!this->peek_token()->is_keyword(KEYWORD_TYPE))
- type = this->type();
- else
- {
- if (is_type_switch != NULL)
- *is_type_switch = true;
- else
- {
- error_at(this->location(),
- "use of %<.(type)%> outside type switch");
- type = Type::make_error_type();
- }
- this->advance_token();
- }
- if (!this->peek_token()->is_op(OPERATOR_RPAREN))
- error_at(this->location(), "missing %<)%>");
- else
- this->advance_token();
- if (is_type_switch != NULL && *is_type_switch)
- return left;
- return Expression::make_type_guard(left, type, location);
- }
- else
- {
- error_at(this->location(), "expected identifier or %<(%>");
- return left;
- }
-}
-
-// Index = "[" Expression "]" .
-// Slice = "[" Expression ":" [ Expression ] "]" .
-
-Expression*
-Parse::index(Expression* expr)
-{
- Location location = this->location();
- go_assert(this->peek_token()->is_op(OPERATOR_LSQUARE));
- this->advance_token();
-
- Expression* start;
- if (!this->peek_token()->is_op(OPERATOR_COLON))
- start = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
- else
- {
- mpz_t zero;
- mpz_init_set_ui(zero, 0);
- start = Expression::make_integer(&zero, NULL, location);
- mpz_clear(zero);
- }
-
- Expression* end = NULL;
- if (this->peek_token()->is_op(OPERATOR_COLON))
- {
- // We use nil to indicate a missing high expression.
- if (this->advance_token()->is_op(OPERATOR_RSQUARE))
- end = Expression::make_nil(this->location());
- else
- end = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
- }
- if (!this->peek_token()->is_op(OPERATOR_RSQUARE))
- error_at(this->location(), "missing %<]%>");
- else
- this->advance_token();
- return Expression::make_index(expr, start, end, location);
-}
-
-// Call = "(" [ ArgumentList [ "," ] ] ")" .
-// ArgumentList = ExpressionList [ "..." ] .
-
-Expression*
-Parse::call(Expression* func)
-{
- go_assert(this->peek_token()->is_op(OPERATOR_LPAREN));
- Expression_list* args = NULL;
- bool is_varargs = false;
- const Token* token = this->advance_token();
- if (!token->is_op(OPERATOR_RPAREN))
- {
- args = this->expression_list(NULL, false, true);
- token = this->peek_token();
- if (token->is_op(OPERATOR_ELLIPSIS))
- {
- is_varargs = true;
- token = this->advance_token();
- }
- }
- if (token->is_op(OPERATOR_COMMA))
- token = this->advance_token();
- if (!token->is_op(OPERATOR_RPAREN))
- error_at(this->location(), "missing %<)%>");
- else
- this->advance_token();
- if (func->is_error_expression())
- return func;
- return Expression::make_call(func, args, is_varargs, func->location());
-}
-
-// Return an expression for a single unqualified identifier.
-
-Expression*
-Parse::id_to_expression(const std::string& name, Location location)
-{
- Named_object* in_function;
- Named_object* named_object = this->gogo_->lookup(name, &in_function);
- if (named_object == NULL)
- named_object = this->gogo_->add_unknown_name(name, location);
-
- if (in_function != NULL
- && in_function != this->gogo_->current_function()
- && (named_object->is_variable() || named_object->is_result_variable()))
- return this->enclosing_var_reference(in_function, named_object,
- location);
-
- switch (named_object->classification())
- {
- case Named_object::NAMED_OBJECT_CONST:
- return Expression::make_const_reference(named_object, location);
- case Named_object::NAMED_OBJECT_VAR:
- case Named_object::NAMED_OBJECT_RESULT_VAR:
- this->mark_var_used(named_object);
- return Expression::make_var_reference(named_object, location);
- case Named_object::NAMED_OBJECT_SINK:
- return Expression::make_sink(location);
- case Named_object::NAMED_OBJECT_FUNC:
- case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
- return Expression::make_func_reference(named_object, NULL, location);
- case Named_object::NAMED_OBJECT_UNKNOWN:
- {
- Unknown_expression* ue =
- Expression::make_unknown_reference(named_object, location);
- if (this->is_erroneous_function_)
- ue->set_no_error_message();
- return ue;
- }
- case Named_object::NAMED_OBJECT_PACKAGE:
- case Named_object::NAMED_OBJECT_TYPE:
- case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
- {
- // These cases can arise for a field name in a composite
- // literal.
- Unknown_expression* ue =
- Expression::make_unknown_reference(named_object, location);
- if (this->is_erroneous_function_)
- ue->set_no_error_message();
- return ue;
- }
- case Named_object::NAMED_OBJECT_ERRONEOUS:
- return Expression::make_error(location);
- default:
- error_at(this->location(), "unexpected type of identifier");
- return Expression::make_error(location);
- }
-}
-
-// Expression = UnaryExpr { binary_op Expression } .
-
-// PRECEDENCE is the precedence of the current operator.
-
-// If MAY_BE_SINK is true, this expression may be "_".
-
-// If MAY_BE_COMPOSITE_LIT is true, this expression may be a composite
-// literal.
-
-// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
-// guard (var := expr.("type") using the literal keyword "type").
-
-// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true
-// if the entire expression is in parentheses.
-
-Expression*
-Parse::expression(Precedence precedence, bool may_be_sink,
- bool may_be_composite_lit, bool* is_type_switch,
- bool *is_parenthesized)
-{
- Expression* left = this->unary_expr(may_be_sink, may_be_composite_lit,
- is_type_switch, is_parenthesized);
-
- while (true)
- {
- if (is_type_switch != NULL && *is_type_switch)
- return left;
-
- const Token* token = this->peek_token();
- if (token->classification() != Token::TOKEN_OPERATOR)
- {
- // Not a binary_op.
- return left;
- }
-
- Precedence right_precedence;
- switch (token->op())
- {
- case OPERATOR_OROR:
- right_precedence = PRECEDENCE_OROR;
- break;
- case OPERATOR_ANDAND:
- right_precedence = PRECEDENCE_ANDAND;
- break;
- case OPERATOR_EQEQ:
- case OPERATOR_NOTEQ:
- case OPERATOR_LT:
- case OPERATOR_LE:
- case OPERATOR_GT:
- case OPERATOR_GE:
- right_precedence = PRECEDENCE_RELOP;
- break;
- case OPERATOR_PLUS:
- case OPERATOR_MINUS:
- case OPERATOR_OR:
- case OPERATOR_XOR:
- right_precedence = PRECEDENCE_ADDOP;
- break;
- case OPERATOR_MULT:
- case OPERATOR_DIV:
- case OPERATOR_MOD:
- case OPERATOR_LSHIFT:
- case OPERATOR_RSHIFT:
- case OPERATOR_AND:
- case OPERATOR_BITCLEAR:
- right_precedence = PRECEDENCE_MULOP;
- break;
- default:
- right_precedence = PRECEDENCE_INVALID;
- break;
- }
-
- if (right_precedence == PRECEDENCE_INVALID)
- {
- // Not a binary_op.
- return left;
- }
-
- if (is_parenthesized != NULL)
- *is_parenthesized = false;
-
- Operator op = token->op();
- Location binop_location = token->location();
-
- if (precedence >= right_precedence)
- {
- // We've already seen A * B, and we see + C. We want to
- // return so that A * B becomes a group.
- return left;
- }
-
- this->advance_token();
-
- left = this->verify_not_sink(left);
- Expression* right = this->expression(right_precedence, false,
- may_be_composite_lit,
- NULL, NULL);
- left = Expression::make_binary(op, left, right, binop_location);
- }
-}
-
-bool
-Parse::expression_may_start_here()
-{
- const Token* token = this->peek_token();
- switch (token->classification())
- {
- case Token::TOKEN_INVALID:
- case Token::TOKEN_EOF:
- return false;
- case Token::TOKEN_KEYWORD:
- switch (token->keyword())
- {
- case KEYWORD_CHAN:
- case KEYWORD_FUNC:
- case KEYWORD_MAP:
- case KEYWORD_STRUCT:
- case KEYWORD_INTERFACE:
- return true;
- default:
- return false;
- }
- case Token::TOKEN_IDENTIFIER:
- return true;
- case Token::TOKEN_STRING:
- return true;
- case Token::TOKEN_OPERATOR:
- switch (token->op())
- {
- case OPERATOR_PLUS:
- case OPERATOR_MINUS:
- case OPERATOR_NOT:
- case OPERATOR_XOR:
- case OPERATOR_MULT:
- case OPERATOR_CHANOP:
- case OPERATOR_AND:
- case OPERATOR_LPAREN:
- case OPERATOR_LSQUARE:
- return true;
- default:
- return false;
- }
- case Token::TOKEN_CHARACTER:
- case Token::TOKEN_INTEGER:
- case Token::TOKEN_FLOAT:
- case Token::TOKEN_IMAGINARY:
- return true;
- default:
- go_unreachable();
- }
-}
-
-// UnaryExpr = unary_op UnaryExpr | PrimaryExpr .
-
-// If MAY_BE_SINK is true, this expression may be "_".
-
-// If MAY_BE_COMPOSITE_LIT is true, this expression may be a composite
-// literal.
-
-// If IS_TYPE_SWITCH is not NULL, this will recognize a type switch
-// guard (var := expr.("type") using the literal keyword "type").
-
-// If IS_PARENTHESIZED is not NULL, *IS_PARENTHESIZED is set to true
-// if the entire expression is in parentheses.
-
-Expression*
-Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
- bool* is_type_switch, bool* is_parenthesized)
-{
- const Token* token = this->peek_token();
-
- // There is a complex parse for <- chan. The choices are
- // Convert x to type <- chan int:
- // (<- chan int)(x)
- // Receive from (x converted to type chan <- chan int):
- // (<- chan <- chan int (x))
- // Convert x to type <- chan (<- chan int).
- // (<- chan <- chan int)(x)
- if (token->is_op(OPERATOR_CHANOP))
- {
- Location location = token->location();
- if (this->advance_token()->is_keyword(KEYWORD_CHAN))
- {
- Expression* expr = this->primary_expr(false, may_be_composite_lit,
- NULL, NULL);
- if (expr->is_error_expression())
- return expr;
- else if (!expr->is_type_expression())
- return Expression::make_receive(expr, location);
- else
- {
- if (expr->type()->is_error_type())
- return expr;
-
- // We picked up "chan TYPE", but it is not a type
- // conversion.
- Channel_type* ct = expr->type()->channel_type();
- if (ct == NULL)
- {
- // This is probably impossible.
- error_at(location, "expected channel type");
- return Expression::make_error(location);
- }
- else if (ct->may_receive())
- {
- // <- chan TYPE.
- Type* t = Type::make_channel_type(false, true,
- ct->element_type());
- return Expression::make_type(t, location);
- }
- else
- {
- // <- chan <- TYPE. Because we skipped the leading
- // <-, we parsed this as chan <- TYPE. With the
- // leading <-, we parse it as <- chan (<- TYPE).
- Type *t = this->reassociate_chan_direction(ct, location);
- return Expression::make_type(t, location);
- }
- }
- }
-
- this->unget_token(Token::make_operator_token(OPERATOR_CHANOP, location));
- token = this->peek_token();
- }
-
- if (token->is_op(OPERATOR_PLUS)
- || token->is_op(OPERATOR_MINUS)
- || token->is_op(OPERATOR_NOT)
- || token->is_op(OPERATOR_XOR)
- || token->is_op(OPERATOR_CHANOP)
- || token->is_op(OPERATOR_MULT)
- || token->is_op(OPERATOR_AND))
- {
- Location location = token->location();
- Operator op = token->op();
- this->advance_token();
-
- Expression* expr = this->unary_expr(false, may_be_composite_lit, NULL,
- NULL);
- if (expr->is_error_expression())
- ;
- else if (op == OPERATOR_MULT && expr->is_type_expression())
- expr = Expression::make_type(Type::make_pointer_type(expr->type()),
- location);
- else if (op == OPERATOR_AND && expr->is_composite_literal())
- expr = Expression::make_heap_composite(expr, location);
- else if (op != OPERATOR_CHANOP)
- expr = Expression::make_unary(op, expr, location);
- else
- expr = Expression::make_receive(expr, location);
- return expr;
- }
- else
- return this->primary_expr(may_be_sink, may_be_composite_lit,
- is_type_switch, is_parenthesized);
-}
-
-// This is called for the obscure case of
-// (<- chan <- chan int)(x)
-// In unary_expr we remove the leading <- and parse the remainder,
-// which gives us
-// chan <- (chan int)
-// When we add the leading <- back in, we really want
-// <- chan (<- chan int)
-// This means that we need to reassociate.
-
-Type*
-Parse::reassociate_chan_direction(Channel_type *ct, Location location)
-{
- Channel_type* ele = ct->element_type()->channel_type();
- if (ele == NULL)
- {
- error_at(location, "parse error");
- return Type::make_error_type();
- }
- Type* sub = ele;
- if (ele->may_send())
- sub = Type::make_channel_type(false, true, ele->element_type());
- else
- sub = this->reassociate_chan_direction(ele, location);
- return Type::make_channel_type(false, true, sub);
-}
-
-// Statement =
-// Declaration | LabeledStmt | SimpleStmt |
-// GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
-// FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
-// DeferStmt .
-
-// LABEL is the label of this statement if it has one.
-
-void
-Parse::statement(Label* label)
-{
- const Token* token = this->peek_token();
- switch (token->classification())
- {
- case Token::TOKEN_KEYWORD:
- {
- switch (token->keyword())
- {
- case KEYWORD_CONST:
- case KEYWORD_TYPE:
- case KEYWORD_VAR:
- this->declaration();
- break;
- case KEYWORD_FUNC:
- case KEYWORD_MAP:
- case KEYWORD_STRUCT:
- case KEYWORD_INTERFACE:
- this->simple_stat(true, NULL, NULL, NULL);
- break;
- case KEYWORD_GO:
- case KEYWORD_DEFER:
- this->go_or_defer_stat();
- break;
- case KEYWORD_RETURN:
- this->return_stat();
- break;
- case KEYWORD_BREAK:
- this->break_stat();
- break;
- case KEYWORD_CONTINUE:
- this->continue_stat();
- break;
- case KEYWORD_GOTO:
- this->goto_stat();
- break;
- case KEYWORD_IF:
- this->if_stat();
- break;
- case KEYWORD_SWITCH:
- this->switch_stat(label);
- break;
- case KEYWORD_SELECT:
- this->select_stat(label);
- break;
- case KEYWORD_FOR:
- this->for_stat(label);
- break;
- default:
- error_at(this->location(), "expected statement");
- this->advance_token();
- break;
- }
- }
- break;
-
- case Token::TOKEN_IDENTIFIER:
- {
- std::string identifier = token->identifier();
- bool is_exported = token->is_identifier_exported();
- Location location = token->location();
- if (this->advance_token()->is_op(OPERATOR_COLON))
- {
- this->advance_token();
- this->labeled_stmt(identifier, location);
- }
- else
- {
- this->unget_token(Token::make_identifier_token(identifier,
- is_exported,
- location));
- this->simple_stat(true, NULL, NULL, NULL);
- }
- }
- break;
-
- case Token::TOKEN_OPERATOR:
- if (token->is_op(OPERATOR_LCURLY))
- {
- Location location = token->location();
- this->gogo_->start_block(location);
- Location end_loc = this->block();
- this->gogo_->add_block(this->gogo_->finish_block(end_loc),
- location);
- }
- else if (!token->is_op(OPERATOR_SEMICOLON))
- this->simple_stat(true, NULL, NULL, NULL);
- break;
-
- case Token::TOKEN_STRING:
- case Token::TOKEN_CHARACTER:
- case Token::TOKEN_INTEGER:
- case Token::TOKEN_FLOAT:
- case Token::TOKEN_IMAGINARY:
- this->simple_stat(true, NULL, NULL, NULL);
- break;
-
- default:
- error_at(this->location(), "expected statement");
- this->advance_token();
- break;
- }
-}
-
-bool
-Parse::statement_may_start_here()
-{
- const Token* token = this->peek_token();
- switch (token->classification())
- {
- case Token::TOKEN_KEYWORD:
- {
- switch (token->keyword())
- {
- case KEYWORD_CONST:
- case KEYWORD_TYPE:
- case KEYWORD_VAR:
- case KEYWORD_FUNC:
- case KEYWORD_MAP:
- case KEYWORD_STRUCT:
- case KEYWORD_INTERFACE:
- case KEYWORD_GO:
- case KEYWORD_DEFER:
- case KEYWORD_RETURN:
- case KEYWORD_BREAK:
- case KEYWORD_CONTINUE:
- case KEYWORD_GOTO:
- case KEYWORD_IF:
- case KEYWORD_SWITCH:
- case KEYWORD_SELECT:
- case KEYWORD_FOR:
- return true;
-
- default:
- return false;
- }
- }
- break;
-
- case Token::TOKEN_IDENTIFIER:
- return true;
-
- case Token::TOKEN_OPERATOR:
- if (token->is_op(OPERATOR_LCURLY)
- || token->is_op(OPERATOR_SEMICOLON))
- return true;
- else
- return this->expression_may_start_here();
-
- case Token::TOKEN_STRING:
- case Token::TOKEN_CHARACTER:
- case Token::TOKEN_INTEGER:
- case Token::TOKEN_FLOAT:
- case Token::TOKEN_IMAGINARY:
- return true;
-
- default:
- return false;
- }
-}
-
-// LabeledStmt = Label ":" Statement .
-// Label = identifier .
-
-void
-Parse::labeled_stmt(const std::string& label_name, Location location)
-{
- Label* label = this->gogo_->add_label_definition(label_name, location);
-
- if (this->peek_token()->is_op(OPERATOR_RCURLY))
- {
- // This is a label at the end of a block. A program is
- // permitted to omit a semicolon here.
- return;
- }
-
- if (!this->statement_may_start_here())
- {
- // Mark the label as used to avoid a useless error about an
- // unused label.
- label->set_is_used();
-
- error_at(location, "missing statement after label");
- this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,
- location));
- return;
- }
-
- this->statement(label);
-}
-
-// SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt |
-// Assignment | ShortVarDecl .
-
-// EmptyStmt was handled in Parse::statement.
-
-// In order to make this work for if and switch statements, if
-// RETURN_EXP is not NULL, and we see an ExpressionStat, we return the
-// expression rather than adding an expression statement to the
-// current block. If we see something other than an ExpressionStat,
-// we add the statement, set *RETURN_EXP to true if we saw a send
-// statement, and return NULL. The handling of send statements is for
-// better error messages.
-
-// If P_RANGE_CLAUSE is not NULL, then this will recognize a
-// RangeClause.
-
-// If P_TYPE_SWITCH is not NULL, this will recognize a type switch
-// guard (var := expr.("type") using the literal keyword "type").
-
-Expression*
-Parse::simple_stat(bool may_be_composite_lit, bool* return_exp,
- Range_clause* p_range_clause, Type_switch* p_type_switch)
-{
- const Token* token = this->peek_token();
-
- // An identifier follow by := is a SimpleVarDecl.
- if (token->is_identifier())
- {
- std::string identifier = token->identifier();
- bool is_exported = token->is_identifier_exported();
- Location location = token->location();
-
- token = this->advance_token();
- if (token->is_op(OPERATOR_COLONEQ)
- || token->is_op(OPERATOR_COMMA))
- {
- identifier = this->gogo_->pack_hidden_name(identifier, is_exported);
- this->simple_var_decl_or_assignment(identifier, location,
- may_be_composite_lit,
- p_range_clause,
- (token->is_op(OPERATOR_COLONEQ)
- ? p_type_switch
- : NULL));
- return NULL;
- }
-
- this->unget_token(Token::make_identifier_token(identifier, is_exported,
- location));
- }
-
- Expression* exp = this->expression(PRECEDENCE_NORMAL, true,
- may_be_composite_lit,
- (p_type_switch == NULL
- ? NULL
- : &p_type_switch->found),
- NULL);
- if (p_type_switch != NULL && p_type_switch->found)
- {
- p_type_switch->name.clear();
- p_type_switch->location = exp->location();
- p_type_switch->expr = this->verify_not_sink(exp);
- return NULL;
- }
- token = this->peek_token();
- if (token->is_op(OPERATOR_CHANOP))
- {
- this->send_stmt(this->verify_not_sink(exp));
- if (return_exp != NULL)
- *return_exp = true;
- }
- else if (token->is_op(OPERATOR_PLUSPLUS)
- || token->is_op(OPERATOR_MINUSMINUS))
- this->inc_dec_stat(this->verify_not_sink(exp));
- else if (token->is_op(OPERATOR_COMMA)
- || token->is_op(OPERATOR_EQ))
- this->assignment(exp, may_be_composite_lit, p_range_clause);
- else if (token->is_op(OPERATOR_PLUSEQ)
- || token->is_op(OPERATOR_MINUSEQ)
- || token->is_op(OPERATOR_OREQ)
- || token->is_op(OPERATOR_XOREQ)
- || token->is_op(OPERATOR_MULTEQ)
- || token->is_op(OPERATOR_DIVEQ)
- || token->is_op(OPERATOR_MODEQ)
- || token->is_op(OPERATOR_LSHIFTEQ)
- || token->is_op(OPERATOR_RSHIFTEQ)
- || token->is_op(OPERATOR_ANDEQ)
- || token->is_op(OPERATOR_BITCLEAREQ))
- this->assignment(this->verify_not_sink(exp), may_be_composite_lit,
- p_range_clause);
- else if (return_exp != NULL)
- return this->verify_not_sink(exp);
- else
- {
- exp = this->verify_not_sink(exp);
-
- if (token->is_op(OPERATOR_COLONEQ))
- {
- if (!exp->is_error_expression())
- error_at(token->location(), "non-name on left side of %<:=%>");
- this->gogo_->mark_locals_used();
- while (!token->is_op(OPERATOR_SEMICOLON)
- && !token->is_eof())
- token = this->advance_token();
- return NULL;
- }
-
- this->expression_stat(exp);
- }
-
- return NULL;
-}
-
-bool
-Parse::simple_stat_may_start_here()
-{
- return this->expression_may_start_here();
-}
-
-// Parse { Statement ";" } which is used in a few places. The list of
-// statements may end with a right curly brace, in which case the
-// semicolon may be omitted.
-
-void
-Parse::statement_list()
-{
- while (this->statement_may_start_here())
- {
- this->statement(NULL);
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- this->advance_token();
- else if (this->peek_token()->is_op(OPERATOR_RCURLY))
- break;
- else
- {
- if (!this->peek_token()->is_eof() || !saw_errors())
- error_at(this->location(), "expected %<;%> or %<}%> or newline");
- if (!this->skip_past_error(OPERATOR_RCURLY))
- return;
- }
- }
-}
-
-bool
-Parse::statement_list_may_start_here()
-{
- return this->statement_may_start_here();
-}
-
-// ExpressionStat = Expression .
-
-void
-Parse::expression_stat(Expression* exp)
-{
- this->gogo_->add_statement(Statement::make_statement(exp, false));
-}
-
-// SendStmt = Channel "&lt;-" Expression .
-// Channel = Expression .
-
-void
-Parse::send_stmt(Expression* channel)
-{
- go_assert(this->peek_token()->is_op(OPERATOR_CHANOP));
- Location loc = this->location();
- this->advance_token();
- Expression* val = this->expression(PRECEDENCE_NORMAL, false, true, NULL,
- NULL);
- Statement* s = Statement::make_send_statement(channel, val, loc);
- this->gogo_->add_statement(s);
-}
-
-// IncDecStat = Expression ( "++" | "--" ) .
-
-void
-Parse::inc_dec_stat(Expression* exp)
-{
- const Token* token = this->peek_token();
-
- // Lvalue maps require special handling.
- if (exp->index_expression() != NULL)
- exp->index_expression()->set_is_lvalue();
-
- if (token->is_op(OPERATOR_PLUSPLUS))
- this->gogo_->add_statement(Statement::make_inc_statement(exp));
- else if (token->is_op(OPERATOR_MINUSMINUS))
- this->gogo_->add_statement(Statement::make_dec_statement(exp));
- else
- go_unreachable();
- this->advance_token();
-}
-
-// Assignment = ExpressionList assign_op ExpressionList .
-
-// EXP is an expression that we have already parsed.
-
-// If MAY_BE_COMPOSITE_LIT is true, an expression on the right hand
-// side may be a composite literal.
-
-// If RANGE_CLAUSE is not NULL, then this will recognize a
-// RangeClause.
-
-void
-Parse::assignment(Expression* expr, bool may_be_composite_lit,
- Range_clause* p_range_clause)
-{
- Expression_list* vars;
- if (!this->peek_token()->is_op(OPERATOR_COMMA))
- {
- vars = new Expression_list();
- vars->push_back(expr);
- }
- else
- {
- this->advance_token();
- vars = this->expression_list(expr, true, may_be_composite_lit);
- }
-
- this->tuple_assignment(vars, may_be_composite_lit, p_range_clause);
-}
-
-// An assignment statement. LHS is the list of expressions which
-// appear on the left hand side.
-
-// If MAY_BE_COMPOSITE_LIT is true, an expression on the right hand
-// side may be a composite literal.
-
-// If RANGE_CLAUSE is not NULL, then this will recognize a
-// RangeClause.
-
-void
-Parse::tuple_assignment(Expression_list* lhs, bool may_be_composite_lit,
- Range_clause* p_range_clause)
-{
- const Token* token = this->peek_token();
- if (!token->is_op(OPERATOR_EQ)
- && !token->is_op(OPERATOR_PLUSEQ)
- && !token->is_op(OPERATOR_MINUSEQ)
- && !token->is_op(OPERATOR_OREQ)
- && !token->is_op(OPERATOR_XOREQ)
- && !token->is_op(OPERATOR_MULTEQ)
- && !token->is_op(OPERATOR_DIVEQ)
- && !token->is_op(OPERATOR_MODEQ)
- && !token->is_op(OPERATOR_LSHIFTEQ)
- && !token->is_op(OPERATOR_RSHIFTEQ)
- && !token->is_op(OPERATOR_ANDEQ)
- && !token->is_op(OPERATOR_BITCLEAREQ))
- {
- error_at(this->location(), "expected assignment operator");
- return;
- }
- Operator op = token->op();
- Location location = token->location();
-
- token = this->advance_token();
-
- if (p_range_clause != NULL && token->is_keyword(KEYWORD_RANGE))
- {
- if (op != OPERATOR_EQ)
- error_at(this->location(), "range clause requires %<=%>");
- this->range_clause_expr(lhs, p_range_clause);
- return;
- }
-
- Expression_list* vals = this->expression_list(NULL, false,
- may_be_composite_lit);
-
- // We've parsed everything; check for errors.
- if (lhs == NULL || vals == NULL)
- return;
- for (Expression_list::const_iterator pe = lhs->begin();
- pe != lhs->end();
- ++pe)
- {
- if ((*pe)->is_error_expression())
- return;
- if (op != OPERATOR_EQ && (*pe)->is_sink_expression())
- error_at((*pe)->location(), "cannot use _ as value");
- }
- for (Expression_list::const_iterator pe = vals->begin();
- pe != vals->end();
- ++pe)
- {
- if ((*pe)->is_error_expression())
- return;
- }
-
- // Map expressions act differently when they are lvalues.
- for (Expression_list::iterator plv = lhs->begin();
- plv != lhs->end();
- ++plv)
- if ((*plv)->index_expression() != NULL)
- (*plv)->index_expression()->set_is_lvalue();
-
- Call_expression* call;
- Index_expression* map_index;
- Receive_expression* receive;
- Type_guard_expression* type_guard;
- if (lhs->size() == vals->size())
- {
- Statement* s;
- if (lhs->size() > 1)
- {
- if (op != OPERATOR_EQ)
- error_at(location, "multiple values only permitted with %<=%>");
- s = Statement::make_tuple_assignment(lhs, vals, location);
- }
- else
- {
- if (op == OPERATOR_EQ)
- s = Statement::make_assignment(lhs->front(), vals->front(),
- location);
- else
- s = Statement::make_assignment_operation(op, lhs->front(),
- vals->front(), location);
- delete lhs;
- delete vals;
- }
- this->gogo_->add_statement(s);
- }
- else if (vals->size() == 1
- && (call = (*vals->begin())->call_expression()) != NULL)
- {
- if (op != OPERATOR_EQ)
- error_at(location, "multiple results only permitted with %<=%>");
- delete vals;
- vals = new Expression_list;
- for (unsigned int i = 0; i < lhs->size(); ++i)
- vals->push_back(Expression::make_call_result(call, i));
- Statement* s = Statement::make_tuple_assignment(lhs, vals, location);
- this->gogo_->add_statement(s);
- }
- else if (lhs->size() == 2
- && vals->size() == 1
- && (map_index = (*vals->begin())->index_expression()) != NULL)
- {
- if (op != OPERATOR_EQ)
- error_at(location, "two values from map requires %<=%>");
- Expression* val = lhs->front();
- Expression* present = lhs->back();
- Statement* s = Statement::make_tuple_map_assignment(val, present,
- map_index, location);
- this->gogo_->add_statement(s);
- }
- else if (lhs->size() == 1
- && vals->size() == 2
- && (map_index = lhs->front()->index_expression()) != NULL)
- {
- if (op != OPERATOR_EQ)
- error_at(location, "assigning tuple to map index requires %<=%>");
- Expression* val = vals->front();
- Expression* should_set = vals->back();
- Statement* s = Statement::make_map_assignment(map_index, val, should_set,
- location);
- this->gogo_->add_statement(s);
- }
- else if (lhs->size() == 2
- && vals->size() == 1
- && (receive = (*vals->begin())->receive_expression()) != NULL)
- {
- if (op != OPERATOR_EQ)
- error_at(location, "two values from receive requires %<=%>");
- Expression* val = lhs->front();
- Expression* success = lhs->back();
- Expression* channel = receive->channel();
- Statement* s = Statement::make_tuple_receive_assignment(val, success,
- channel,
- location);
- this->gogo_->add_statement(s);
- }
- else if (lhs->size() == 2
- && vals->size() == 1
- && (type_guard = (*vals->begin())->type_guard_expression()) != NULL)
- {
- if (op != OPERATOR_EQ)
- error_at(location, "two values from type guard requires %<=%>");
- Expression* val = lhs->front();
- Expression* ok = lhs->back();
- Expression* expr = type_guard->expr();
- Type* type = type_guard->type();
- Statement* s = Statement::make_tuple_type_guard_assignment(val, ok,
- expr, type,
- location);
- this->gogo_->add_statement(s);
- }
- else
- {
- error_at(location, "number of variables does not match number of values");
- }
-}
-
-// GoStat = "go" Expression .
-// DeferStat = "defer" Expression .
-
-void
-Parse::go_or_defer_stat()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_GO)
- || this->peek_token()->is_keyword(KEYWORD_DEFER));
- bool is_go = this->peek_token()->is_keyword(KEYWORD_GO);
- Location stat_location = this->location();
-
- this->advance_token();
- Location expr_location = this->location();
-
- bool is_parenthesized = false;
- Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true, NULL,
- &is_parenthesized);
- Call_expression* call_expr = expr->call_expression();
- if (is_parenthesized || call_expr == NULL)
- {
- error_at(expr_location, "argument to go/defer must be function call");
- return;
- }
-
- // Make it easier to simplify go/defer statements by putting every
- // statement in its own block.
- this->gogo_->start_block(stat_location);
- Statement* stat;
- if (is_go)
- stat = Statement::make_go_statement(call_expr, stat_location);
- else
- stat = Statement::make_defer_statement(call_expr, stat_location);
- this->gogo_->add_statement(stat);
- this->gogo_->add_block(this->gogo_->finish_block(stat_location),
- stat_location);
-}
-
-// ReturnStat = "return" [ ExpressionList ] .
-
-void
-Parse::return_stat()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_RETURN));
- Location location = this->location();
- this->advance_token();
- Expression_list* vals = NULL;
- if (this->expression_may_start_here())
- vals = this->expression_list(NULL, false, true);
- this->gogo_->add_statement(Statement::make_return_statement(vals, location));
-
- if (vals == NULL
- && this->gogo_->current_function()->func_value()->results_are_named())
- {
- Named_object* function = this->gogo_->current_function();
- Function::Results* results = function->func_value()->result_variables();
- for (Function::Results::const_iterator p = results->begin();
- p != results->end();
- ++p)
- {
- Named_object* no = this->gogo_->lookup((*p)->name(), NULL);
- if (no == NULL)
- go_assert(saw_errors());
- else if (!no->is_result_variable())
- error_at(location, "%qs is shadowed during return",
- (*p)->message_name().c_str());
- }
- }
-}
-
-// IfStmt = "if" [ SimpleStmt ";" ] Expression Block
-// [ "else" ( IfStmt | Block ) ] .
-
-void
-Parse::if_stat()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_IF));
- Location location = this->location();
- this->advance_token();
-
- this->gogo_->start_block(location);
-
- bool saw_simple_stat = false;
- Expression* cond = NULL;
- bool saw_send_stmt = false;
- if (this->simple_stat_may_start_here())
- {
- cond = this->simple_stat(false, &saw_send_stmt, NULL, NULL);
- saw_simple_stat = true;
- }
- if (cond != NULL && this->peek_token()->is_op(OPERATOR_SEMICOLON))
- {
- // The SimpleStat is an expression statement.
- this->expression_stat(cond);
- cond = NULL;
- }
- if (cond == NULL)
- {
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- this->advance_token();
- else if (saw_simple_stat)
- {
- if (saw_send_stmt)
- error_at(this->location(),
- ("send statement used as value; "
- "use select for non-blocking send"));
- else
- error_at(this->location(),
- "expected %<;%> after statement in if expression");
- if (!this->expression_may_start_here())
- cond = Expression::make_error(this->location());
- }
- if (cond == NULL && this->peek_token()->is_op(OPERATOR_LCURLY))
- {
- error_at(this->location(),
- "missing condition in if statement");
- cond = Expression::make_error(this->location());
- }
- if (cond == NULL)
- cond = this->expression(PRECEDENCE_NORMAL, false, false, NULL, NULL);
- }
-
- this->gogo_->start_block(this->location());
- Location end_loc = this->block();
- Block* then_block = this->gogo_->finish_block(end_loc);
-
- // Check for the easy error of a newline before "else".
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- {
- Location semi_loc = this->location();
- if (this->advance_token()->is_keyword(KEYWORD_ELSE))
- error_at(this->location(),
- "unexpected semicolon or newline before %<else%>");
- else
- this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,
- semi_loc));
- }
-
- Block* else_block = NULL;
- if (this->peek_token()->is_keyword(KEYWORD_ELSE))
- {
- this->gogo_->start_block(this->location());
- const Token* token = this->advance_token();
- if (token->is_keyword(KEYWORD_IF))
- this->if_stat();
- else if (token->is_op(OPERATOR_LCURLY))
- this->block();
- else
- {
- error_at(this->location(), "expected %<if%> or %<{%>");
- this->statement(NULL);
- }
- else_block = this->gogo_->finish_block(this->location());
- }
-
- this->gogo_->add_statement(Statement::make_if_statement(cond, then_block,
- else_block,
- location));
-
- this->gogo_->add_block(this->gogo_->finish_block(this->location()),
- location);
-}
-
-// SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
-// ExprSwitchStmt = "switch" [ [ SimpleStat ] ";" ] [ Expression ]
-// "{" { ExprCaseClause } "}" .
-// TypeSwitchStmt = "switch" [ [ SimpleStat ] ";" ] TypeSwitchGuard
-// "{" { TypeCaseClause } "}" .
-// TypeSwitchGuard = [ identifier ":=" ] Expression "." "(" "type" ")" .
-
-void
-Parse::switch_stat(Label* label)
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_SWITCH));
- Location location = this->location();
- this->advance_token();
-
- this->gogo_->start_block(location);
-
- bool saw_simple_stat = false;
- Expression* switch_val = NULL;
- bool saw_send_stmt;
- Type_switch type_switch;
- bool have_type_switch_block = false;
- if (this->simple_stat_may_start_here())
- {
- switch_val = this->simple_stat(false, &saw_send_stmt, NULL,
- &type_switch);
- saw_simple_stat = true;
- }
- if (switch_val != NULL && this->peek_token()->is_op(OPERATOR_SEMICOLON))
- {
- // The SimpleStat is an expression statement.
- this->expression_stat(switch_val);
- switch_val = NULL;
- }
- if (switch_val == NULL && !type_switch.found)
- {
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- this->advance_token();
- else if (saw_simple_stat)
- {
- if (saw_send_stmt)
- error_at(this->location(),
- ("send statement used as value; "
- "use select for non-blocking send"));
- else
- error_at(this->location(),
- "expected %<;%> after statement in switch expression");
- }
- if (!this->peek_token()->is_op(OPERATOR_LCURLY))
- {
- if (this->peek_token()->is_identifier())
- {
- const Token* token = this->peek_token();
- std::string identifier = token->identifier();
- bool is_exported = token->is_identifier_exported();
- Location id_loc = token->location();
-
- token = this->advance_token();
- bool is_coloneq = token->is_op(OPERATOR_COLONEQ);
- this->unget_token(Token::make_identifier_token(identifier,
- is_exported,
- id_loc));
- if (is_coloneq)
- {
- // This must be a TypeSwitchGuard. It is in a
- // different block from any initial SimpleStat.
- if (saw_simple_stat)
- {
- this->gogo_->start_block(id_loc);
- have_type_switch_block = true;
- }
-
- switch_val = this->simple_stat(false, &saw_send_stmt, NULL,
- &type_switch);
- if (!type_switch.found)
- {
- if (switch_val == NULL
- || !switch_val->is_error_expression())
- {
- error_at(id_loc, "expected type switch assignment");
- switch_val = Expression::make_error(id_loc);
- }
- }
- }
- }
- if (switch_val == NULL && !type_switch.found)
- {
- switch_val = this->expression(PRECEDENCE_NORMAL, false, false,
- &type_switch.found, NULL);
- if (type_switch.found)
- {
- type_switch.name.clear();
- type_switch.expr = switch_val;
- type_switch.location = switch_val->location();
- }
- }
- }
- }
-
- if (!this->peek_token()->is_op(OPERATOR_LCURLY))
- {
- Location token_loc = this->location();
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON)
- && this->advance_token()->is_op(OPERATOR_LCURLY))
- error_at(token_loc, "unexpected semicolon or newline before %<{%>");
- else if (this->peek_token()->is_op(OPERATOR_COLONEQ))
- {
- error_at(token_loc, "invalid variable name");
- this->advance_token();
- this->expression(PRECEDENCE_NORMAL, false, false,
- &type_switch.found, NULL);
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- this->advance_token();
- if (!this->peek_token()->is_op(OPERATOR_LCURLY))
- {
- if (have_type_switch_block)
- this->gogo_->add_block(this->gogo_->finish_block(location),
- location);
- this->gogo_->add_block(this->gogo_->finish_block(location),
- location);
- return;
- }
- if (type_switch.found)
- type_switch.expr = Expression::make_error(location);
- }
- else
- {
- error_at(this->location(), "expected %<{%>");
- if (have_type_switch_block)
- this->gogo_->add_block(this->gogo_->finish_block(this->location()),
- location);
- this->gogo_->add_block(this->gogo_->finish_block(this->location()),
- location);
- return;
- }
- }
- this->advance_token();
-
- Statement* statement;
- if (type_switch.found)
- statement = this->type_switch_body(label, type_switch, location);
- else
- statement = this->expr_switch_body(label, switch_val, location);
-
- if (statement != NULL)
- this->gogo_->add_statement(statement);
-
- if (have_type_switch_block)
- this->gogo_->add_block(this->gogo_->finish_block(this->location()),
- location);
-
- this->gogo_->add_block(this->gogo_->finish_block(this->location()),
- location);
-}
-
-// The body of an expression switch.
-// "{" { ExprCaseClause } "}"
-
-Statement*
-Parse::expr_switch_body(Label* label, Expression* switch_val,
- Location location)
-{
- Switch_statement* statement = Statement::make_switch_statement(switch_val,
- location);
-
- this->push_break_statement(statement, label);
-
- Case_clauses* case_clauses = new Case_clauses();
- bool saw_default = false;
- while (!this->peek_token()->is_op(OPERATOR_RCURLY))
- {
- if (this->peek_token()->is_eof())
- {
- if (!saw_errors())
- error_at(this->location(), "missing %<}%>");
- return NULL;
- }
- this->expr_case_clause(case_clauses, &saw_default);
- }
- this->advance_token();
-
- statement->add_clauses(case_clauses);
-
- this->pop_break_statement();
-
- return statement;
-}
-
-// ExprCaseClause = ExprSwitchCase ":" [ StatementList ] .
-// FallthroughStat = "fallthrough" .
-
-void
-Parse::expr_case_clause(Case_clauses* clauses, bool* saw_default)
-{
- Location location = this->location();
-
- bool is_default = false;
- Expression_list* vals = this->expr_switch_case(&is_default);
-
- if (!this->peek_token()->is_op(OPERATOR_COLON))
- {
- if (!saw_errors())
- error_at(this->location(), "expected %<:%>");
- return;
- }
- else
- this->advance_token();
-
- Block* statements = NULL;
- if (this->statement_list_may_start_here())
- {
- this->gogo_->start_block(this->location());
- this->statement_list();
- statements = this->gogo_->finish_block(this->location());
- }
-
- bool is_fallthrough = false;
- if (this->peek_token()->is_keyword(KEYWORD_FALLTHROUGH))
- {
- is_fallthrough = true;
- if (this->advance_token()->is_op(OPERATOR_SEMICOLON))
- this->advance_token();
- }
-
- if (is_default)
- {
- if (*saw_default)
- {
- error_at(location, "multiple defaults in switch");
- return;
- }
- *saw_default = true;
- }
-
- if (is_default || vals != NULL)
- clauses->add(vals, is_default, statements, is_fallthrough, location);
-}
-
-// ExprSwitchCase = "case" ExpressionList | "default" .
-
-Expression_list*
-Parse::expr_switch_case(bool* is_default)
-{
- const Token* token = this->peek_token();
- if (token->is_keyword(KEYWORD_CASE))
- {
- this->advance_token();
- return this->expression_list(NULL, false, true);
- }
- else if (token->is_keyword(KEYWORD_DEFAULT))
- {
- this->advance_token();
- *is_default = true;
- return NULL;
- }
- else
- {
- if (!saw_errors())
- error_at(this->location(), "expected %<case%> or %<default%>");
- if (!token->is_op(OPERATOR_RCURLY))
- this->advance_token();
- return NULL;
- }
-}
-
-// The body of a type switch.
-// "{" { TypeCaseClause } "}" .
-
-Statement*
-Parse::type_switch_body(Label* label, const Type_switch& type_switch,
- Location location)
-{
- Named_object* switch_no = NULL;
- if (!type_switch.name.empty())
- {
- if (Gogo::is_sink_name(type_switch.name))
- error_at(type_switch.location,
- "no new variables on left side of %<:=%>");
- else
- {
- Variable* switch_var = new Variable(NULL, type_switch.expr, false,
- false, false,
- type_switch.location);
- switch_no = this->gogo_->add_variable(type_switch.name, switch_var);
- }
- }
-
- Type_switch_statement* statement =
- Statement::make_type_switch_statement(switch_no,
- (switch_no == NULL
- ? type_switch.expr
- : NULL),
- location);
-
- this->push_break_statement(statement, label);
-
- Type_case_clauses* case_clauses = new Type_case_clauses();
- bool saw_default = false;
- while (!this->peek_token()->is_op(OPERATOR_RCURLY))
- {
- if (this->peek_token()->is_eof())
- {
- error_at(this->location(), "missing %<}%>");
- return NULL;
- }
- this->type_case_clause(switch_no, case_clauses, &saw_default);
- }
- this->advance_token();
-
- statement->add_clauses(case_clauses);
-
- this->pop_break_statement();
-
- return statement;
-}
-
-// TypeCaseClause = TypeSwitchCase ":" [ StatementList ] .
-
-void
-Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses,
- bool* saw_default)
-{
- Location location = this->location();
-
- std::vector<Type*> types;
- bool is_default = false;
- this->type_switch_case(&types, &is_default);
-
- if (!this->peek_token()->is_op(OPERATOR_COLON))
- error_at(this->location(), "expected %<:%>");
- else
- this->advance_token();
-
- Block* statements = NULL;
- if (this->statement_list_may_start_here())
- {
- this->gogo_->start_block(this->location());
- if (switch_no != NULL && types.size() == 1)
- {
- Type* type = types.front();
- Expression* init = Expression::make_var_reference(switch_no,
- location);
- init = Expression::make_type_guard(init, type, location);
- Variable* v = new Variable(type, init, false, false, false,
- location);
- v->set_is_type_switch_var();
- Named_object* no = this->gogo_->add_variable(switch_no->name(), v);
-
- // We don't want to issue an error if the compiler
- // introduced special variable is not used. Instead we want
- // to issue an error if the variable defined by the switch
- // is not used. That is handled via type_switch_vars_ and
- // Parse::mark_var_used.
- v->set_is_used();
- this->type_switch_vars_[no] = switch_no;
- }
- this->statement_list();
- statements = this->gogo_->finish_block(this->location());
- }
-
- if (this->peek_token()->is_keyword(KEYWORD_FALLTHROUGH))
- {
- error_at(this->location(),
- "fallthrough is not permitted in a type switch");
- if (this->advance_token()->is_op(OPERATOR_SEMICOLON))
- this->advance_token();
- }
-
- if (is_default)
- {
- go_assert(types.empty());
- if (*saw_default)
- {
- error_at(location, "multiple defaults in type switch");
- return;
- }
- *saw_default = true;
- clauses->add(NULL, false, true, statements, location);
- }
- else if (!types.empty())
- {
- for (std::vector<Type*>::const_iterator p = types.begin();
- p + 1 != types.end();
- ++p)
- 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"
-
-// We accept a comma separated list of types.
-
-void
-Parse::type_switch_case(std::vector<Type*>* types, bool* is_default)
-{
- const Token* token = this->peek_token();
- if (token->is_keyword(KEYWORD_CASE))
- {
- this->advance_token();
- while (true)
- {
- Type* t = this->type();
-
- if (!t->is_error_type())
- types->push_back(t);
- else
- {
- this->gogo_->mark_locals_used();
- token = this->peek_token();
- while (!token->is_op(OPERATOR_COLON)
- && !token->is_op(OPERATOR_COMMA)
- && !token->is_op(OPERATOR_RCURLY)
- && !token->is_eof())
- token = this->advance_token();
- }
-
- if (!this->peek_token()->is_op(OPERATOR_COMMA))
- break;
- this->advance_token();
- }
- }
- else if (token->is_keyword(KEYWORD_DEFAULT))
- {
- this->advance_token();
- *is_default = true;
- }
- else
- {
- error_at(this->location(), "expected %<case%> or %<default%>");
- if (!token->is_op(OPERATOR_RCURLY))
- this->advance_token();
- }
-}
-
-// SelectStat = "select" "{" { CommClause } "}" .
-
-void
-Parse::select_stat(Label* label)
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_SELECT));
- Location location = this->location();
- const Token* token = this->advance_token();
-
- if (!token->is_op(OPERATOR_LCURLY))
- {
- Location token_loc = token->location();
- if (token->is_op(OPERATOR_SEMICOLON)
- && this->advance_token()->is_op(OPERATOR_LCURLY))
- error_at(token_loc, "unexpected semicolon or newline before %<{%>");
- else
- {
- error_at(this->location(), "expected %<{%>");
- return;
- }
- }
- this->advance_token();
-
- Select_statement* statement = Statement::make_select_statement(location);
-
- this->push_break_statement(statement, label);
-
- Select_clauses* select_clauses = new Select_clauses();
- bool saw_default = false;
- while (!this->peek_token()->is_op(OPERATOR_RCURLY))
- {
- if (this->peek_token()->is_eof())
- {
- error_at(this->location(), "expected %<}%>");
- return;
- }
- this->comm_clause(select_clauses, &saw_default);
- }
-
- this->advance_token();
-
- statement->add_clauses(select_clauses);
-
- this->pop_break_statement();
-
- this->gogo_->add_statement(statement);
-}
-
-// CommClause = CommCase ":" { Statement ";" } .
-
-void
-Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
-{
- Location location = this->location();
- bool is_send = false;
- Expression* channel = NULL;
- Expression* val = NULL;
- Expression* closed = NULL;
- std::string varname;
- std::string closedname;
- bool is_default = false;
- bool got_case = this->comm_case(&is_send, &channel, &val, &closed,
- &varname, &closedname, &is_default);
-
- if (!is_send
- && varname.empty()
- && closedname.empty()
- && val != NULL
- && val->index_expression() != NULL)
- val->index_expression()->set_is_lvalue();
-
- if (this->peek_token()->is_op(OPERATOR_COLON))
- this->advance_token();
- else
- error_at(this->location(), "expected colon");
-
- this->gogo_->start_block(this->location());
-
- Named_object* var = NULL;
- if (!varname.empty())
- {
- // FIXME: LOCATION is slightly wrong here.
- Variable* v = new Variable(NULL, channel, false, false, false,
- location);
- v->set_type_from_chan_element();
- var = this->gogo_->add_variable(varname, v);
- }
-
- Named_object* closedvar = NULL;
- if (!closedname.empty())
- {
- // FIXME: LOCATION is slightly wrong here.
- Variable* v = new Variable(Type::lookup_bool_type(), NULL,
- false, false, false, location);
- closedvar = this->gogo_->add_variable(closedname, v);
- }
-
- this->statement_list();
-
- Block* statements = this->gogo_->finish_block(this->location());
-
- if (is_default)
- {
- if (*saw_default)
- {
- error_at(location, "multiple defaults in select");
- return;
- }
- *saw_default = true;
- }
-
- if (got_case)
- clauses->add(is_send, channel, val, closed, var, closedvar, is_default,
- statements, location);
- else if (statements != NULL)
- {
- // Add the statements to make sure that any names they define
- // are traversed.
- this->gogo_->add_block(statements, location);
- }
-}
-
-// CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
-
-bool
-Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
- Expression** closed, std::string* varname,
- std::string* closedname, bool* is_default)
-{
- const Token* token = this->peek_token();
- if (token->is_keyword(KEYWORD_DEFAULT))
- {
- this->advance_token();
- *is_default = true;
- }
- else if (token->is_keyword(KEYWORD_CASE))
- {
- this->advance_token();
- if (!this->send_or_recv_stmt(is_send, channel, val, closed, varname,
- closedname))
- return false;
- }
- else
- {
- error_at(this->location(), "expected %<case%> or %<default%>");
- if (!token->is_op(OPERATOR_RCURLY))
- this->advance_token();
- return false;
- }
-
- return true;
-}
-
-// RecvStmt = [ Expression [ "," Expression ] ( "=" | ":=" ) ] RecvExpr .
-// RecvExpr = Expression .
-
-bool
-Parse::send_or_recv_stmt(bool* is_send, Expression** channel, Expression** val,
- Expression** closed, std::string* varname,
- std::string* closedname)
-{
- const Token* token = this->peek_token();
- bool saw_comma = false;
- bool closed_is_id = false;
- if (token->is_identifier())
- {
- Gogo* gogo = this->gogo_;
- std::string recv_var = token->identifier();
- bool is_rv_exported = token->is_identifier_exported();
- Location recv_var_loc = token->location();
- token = this->advance_token();
- if (token->is_op(OPERATOR_COLONEQ))
- {
- // case rv := <-c:
- this->advance_token();
- Expression* e = this->expression(PRECEDENCE_NORMAL, false, false,
- NULL, NULL);
- Receive_expression* re = e->receive_expression();
- if (re == NULL)
- {
- if (!e->is_error_expression())
- error_at(this->location(), "expected receive expression");
- return false;
- }
- if (recv_var == "_")
- {
- error_at(recv_var_loc,
- "no new variables on left side of %<:=%>");
- recv_var = "blank";
- }
- *is_send = false;
- *varname = gogo->pack_hidden_name(recv_var, is_rv_exported);
- *channel = re->channel();
- return true;
- }
- else if (token->is_op(OPERATOR_COMMA))
- {
- token = this->advance_token();
- if (token->is_identifier())
- {
- std::string recv_closed = token->identifier();
- bool is_rc_exported = token->is_identifier_exported();
- Location recv_closed_loc = token->location();
- closed_is_id = true;
-
- token = this->advance_token();
- if (token->is_op(OPERATOR_COLONEQ))
- {
- // case rv, rc := <-c:
- this->advance_token();
- Expression* e = this->expression(PRECEDENCE_NORMAL, false,
- false, NULL, NULL);
- Receive_expression* re = e->receive_expression();
- if (re == NULL)
- {
- if (!e->is_error_expression())
- error_at(this->location(),
- "expected receive expression");
- return false;
- }
- if (recv_var == "_" && recv_closed == "_")
- {
- error_at(recv_var_loc,
- "no new variables on left side of %<:=%>");
- recv_var = "blank";
- }
- *is_send = false;
- if (recv_var != "_")
- *varname = gogo->pack_hidden_name(recv_var,
- is_rv_exported);
- if (recv_closed != "_")
- *closedname = gogo->pack_hidden_name(recv_closed,
- is_rc_exported);
- *channel = re->channel();
- return true;
- }
-
- this->unget_token(Token::make_identifier_token(recv_closed,
- is_rc_exported,
- recv_closed_loc));
- }
-
- *val = this->id_to_expression(gogo->pack_hidden_name(recv_var,
- is_rv_exported),
- recv_var_loc);
- saw_comma = true;
- }
- else
- this->unget_token(Token::make_identifier_token(recv_var,
- is_rv_exported,
- recv_var_loc));
- }
-
- // If SAW_COMMA is false, then we are looking at the start of the
- // send or receive expression. If SAW_COMMA is true, then *VAL is
- // set and we just read a comma.
-
- Expression* e;
- if (saw_comma || !this->peek_token()->is_op(OPERATOR_CHANOP))
- e = this->expression(PRECEDENCE_NORMAL, true, true, NULL, NULL);
- else
- {
- // case <-c:
- *is_send = false;
- this->advance_token();
- *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
-
- // The next token should be ':'. If it is '<-', then we have
- // case <-c <- v:
- // which is to say, send on a channel received from a channel.
- if (!this->peek_token()->is_op(OPERATOR_CHANOP))
- return true;
-
- e = Expression::make_receive(*channel, (*channel)->location());
- }
-
- if (this->peek_token()->is_op(OPERATOR_EQ))
- {
- if (!this->advance_token()->is_op(OPERATOR_CHANOP))
- {
- error_at(this->location(), "missing %<<-%>");
- return false;
- }
- *is_send = false;
- this->advance_token();
- *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
- if (saw_comma)
- {
- // case v, e = <-c:
- // *VAL is already set.
- if (!e->is_sink_expression())
- *closed = e;
- }
- else
- {
- // case v = <-c:
- if (!e->is_sink_expression())
- *val = e;
- }
- return true;
- }
-
- if (saw_comma)
- {
- if (closed_is_id)
- error_at(this->location(), "expected %<=%> or %<:=%>");
- else
- error_at(this->location(), "expected %<=%>");
- return false;
- }
-
- if (this->peek_token()->is_op(OPERATOR_CHANOP))
- {
- // case c <- v:
- *is_send = true;
- *channel = this->verify_not_sink(e);
- this->advance_token();
- *val = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
- return true;
- }
-
- error_at(this->location(), "expected %<<-%> or %<=%>");
- return false;
-}
-
-// ForStat = "for" [ Condition | ForClause | RangeClause ] Block .
-// Condition = Expression .
-
-void
-Parse::for_stat(Label* label)
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_FOR));
- Location location = this->location();
- const Token* token = this->advance_token();
-
- // Open a block to hold any variables defined in the init statement
- // of the for statement.
- this->gogo_->start_block(location);
-
- Block* init = NULL;
- Expression* cond = NULL;
- Block* post = NULL;
- Range_clause range_clause;
-
- if (!token->is_op(OPERATOR_LCURLY))
- {
- if (token->is_keyword(KEYWORD_VAR))
- {
- error_at(this->location(),
- "var declaration not allowed in for initializer");
- this->var_decl();
- }
-
- if (token->is_op(OPERATOR_SEMICOLON))
- this->for_clause(&cond, &post);
- else
- {
- // We might be looking at a Condition, an InitStat, or a
- // RangeClause.
- bool saw_send_stmt;
- cond = this->simple_stat(false, &saw_send_stmt, &range_clause, NULL);
- if (!this->peek_token()->is_op(OPERATOR_SEMICOLON))
- {
- if (cond == NULL && !range_clause.found)
- {
- if (saw_send_stmt)
- error_at(this->location(),
- ("send statement used as value; "
- "use select for non-blocking send"));
- else
- error_at(this->location(), "parse error in for statement");
- }
- }
- else
- {
- if (range_clause.found)
- error_at(this->location(), "parse error after range clause");
-
- if (cond != NULL)
- {
- // COND is actually an expression statement for
- // InitStat at the start of a ForClause.
- this->expression_stat(cond);
- cond = NULL;
- }
-
- this->for_clause(&cond, &post);
- }
- }
- }
-
- // Build the For_statement and note that it is the current target
- // for break and continue statements.
-
- For_statement* sfor;
- For_range_statement* srange;
- Statement* s;
- if (!range_clause.found)
- {
- sfor = Statement::make_for_statement(init, cond, post, location);
- s = sfor;
- srange = NULL;
- }
- else
- {
- srange = Statement::make_for_range_statement(range_clause.index,
- range_clause.value,
- range_clause.range,
- location);
- s = srange;
- sfor = NULL;
- }
-
- this->push_break_statement(s, label);
- this->push_continue_statement(s, label);
-
- // Gather the block of statements in the loop and add them to the
- // For_statement.
-
- this->gogo_->start_block(this->location());
- Location end_loc = this->block();
- Block* statements = this->gogo_->finish_block(end_loc);
-
- if (sfor != NULL)
- sfor->add_statements(statements);
- else
- srange->add_statements(statements);
-
- // This is no longer the break/continue target.
- this->pop_break_statement();
- this->pop_continue_statement();
-
- // Add the For_statement to the list of statements, and close out
- // the block we started to hold any variables defined in the for
- // statement.
-
- this->gogo_->add_statement(s);
-
- this->gogo_->add_block(this->gogo_->finish_block(this->location()),
- location);
-}
-
-// ForClause = [ InitStat ] ";" [ Condition ] ";" [ PostStat ] .
-// InitStat = SimpleStat .
-// PostStat = SimpleStat .
-
-// We have already read InitStat at this point.
-
-void
-Parse::for_clause(Expression** cond, Block** post)
-{
- go_assert(this->peek_token()->is_op(OPERATOR_SEMICOLON));
- this->advance_token();
- if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
- *cond = NULL;
- else if (this->peek_token()->is_op(OPERATOR_LCURLY))
- {
- error_at(this->location(),
- "unexpected semicolon or newline before %<{%>");
- *cond = NULL;
- *post = NULL;
- return;
- }
- else
- *cond = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL);
- if (!this->peek_token()->is_op(OPERATOR_SEMICOLON))
- error_at(this->location(), "expected semicolon");
- else
- this->advance_token();
-
- if (this->peek_token()->is_op(OPERATOR_LCURLY))
- *post = NULL;
- else
- {
- this->gogo_->start_block(this->location());
- this->simple_stat(false, NULL, NULL, NULL);
- *post = this->gogo_->finish_block(this->location());
- }
-}
-
-// RangeClause = IdentifierList ( "=" | ":=" ) "range" Expression .
-
-// This is the := version. It is called with a list of identifiers.
-
-void
-Parse::range_clause_decl(const Typed_identifier_list* til,
- Range_clause* p_range_clause)
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_RANGE));
- Location location = this->location();
-
- p_range_clause->found = true;
-
- go_assert(til->size() >= 1);
- if (til->size() > 2)
- error_at(this->location(), "too many variables for range clause");
-
- this->advance_token();
- Expression* expr = this->expression(PRECEDENCE_NORMAL, false, false, NULL,
- NULL);
- p_range_clause->range = expr;
-
- bool any_new = false;
-
- const Typed_identifier* pti = &til->front();
- Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new,
- NULL, NULL);
- if (any_new && no->is_variable())
- no->var_value()->set_type_from_range_index();
- p_range_clause->index = Expression::make_var_reference(no, location);
-
- if (til->size() == 1)
- p_range_clause->value = NULL;
- else
- {
- pti = &til->back();
- bool is_new = false;
- no = this->init_var(*pti, NULL, expr, true, true, &is_new, NULL, NULL);
- if (is_new && no->is_variable())
- no->var_value()->set_type_from_range_value();
- if (is_new)
- any_new = true;
- p_range_clause->value = Expression::make_var_reference(no, location);
- }
-
- if (!any_new)
- error_at(location, "variables redeclared but no variable is new");
-}
-
-// The = version of RangeClause. This is called with a list of
-// expressions.
-
-void
-Parse::range_clause_expr(const Expression_list* vals,
- Range_clause* p_range_clause)
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_RANGE));
-
- p_range_clause->found = true;
-
- go_assert(vals->size() >= 1);
- if (vals->size() > 2)
- error_at(this->location(), "too many variables for range clause");
-
- this->advance_token();
- p_range_clause->range = this->expression(PRECEDENCE_NORMAL, false, false,
- NULL, NULL);
-
- p_range_clause->index = vals->front();
- if (vals->size() == 1)
- p_range_clause->value = NULL;
- else
- p_range_clause->value = vals->back();
-}
-
-// Push a statement on the break stack.
-
-void
-Parse::push_break_statement(Statement* enclosing, Label* label)
-{
- if (this->break_stack_ == NULL)
- this->break_stack_ = new Bc_stack();
- this->break_stack_->push_back(std::make_pair(enclosing, label));
-}
-
-// Push a statement on the continue stack.
-
-void
-Parse::push_continue_statement(Statement* enclosing, Label* label)
-{
- if (this->continue_stack_ == NULL)
- this->continue_stack_ = new Bc_stack();
- this->continue_stack_->push_back(std::make_pair(enclosing, label));
-}
-
-// Pop the break stack.
-
-void
-Parse::pop_break_statement()
-{
- this->break_stack_->pop_back();
-}
-
-// Pop the continue stack.
-
-void
-Parse::pop_continue_statement()
-{
- this->continue_stack_->pop_back();
-}
-
-// Find a break or continue statement given a label name.
-
-Statement*
-Parse::find_bc_statement(const Bc_stack* bc_stack, const std::string& label)
-{
- if (bc_stack == NULL)
- return NULL;
- for (Bc_stack::const_reverse_iterator p = bc_stack->rbegin();
- p != bc_stack->rend();
- ++p)
- {
- if (p->second != NULL && p->second->name() == label)
- {
- p->second->set_is_used();
- return p->first;
- }
- }
- return NULL;
-}
-
-// BreakStat = "break" [ identifier ] .
-
-void
-Parse::break_stat()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_BREAK));
- Location location = this->location();
-
- const Token* token = this->advance_token();
- Statement* enclosing;
- if (!token->is_identifier())
- {
- if (this->break_stack_ == NULL || this->break_stack_->empty())
- {
- error_at(this->location(),
- "break statement not within for or switch or select");
- return;
- }
- enclosing = this->break_stack_->back().first;
- }
- else
- {
- enclosing = this->find_bc_statement(this->break_stack_,
- token->identifier());
- if (enclosing == NULL)
- {
- // If there is a label with this name, mark it as used to
- // avoid a useless error about an unused label.
- this->gogo_->add_label_reference(token->identifier(),
- Linemap::unknown_location(), false);
-
- error_at(token->location(), "invalid break label %qs",
- Gogo::message_name(token->identifier()).c_str());
- this->advance_token();
- return;
- }
- this->advance_token();
- }
-
- Unnamed_label* label;
- if (enclosing->classification() == Statement::STATEMENT_FOR)
- label = enclosing->for_statement()->break_label();
- else if (enclosing->classification() == Statement::STATEMENT_FOR_RANGE)
- label = enclosing->for_range_statement()->break_label();
- else if (enclosing->classification() == Statement::STATEMENT_SWITCH)
- label = enclosing->switch_statement()->break_label();
- else if (enclosing->classification() == Statement::STATEMENT_TYPE_SWITCH)
- label = enclosing->type_switch_statement()->break_label();
- else if (enclosing->classification() == Statement::STATEMENT_SELECT)
- label = enclosing->select_statement()->break_label();
- else
- go_unreachable();
-
- this->gogo_->add_statement(Statement::make_break_statement(label,
- location));
-}
-
-// ContinueStat = "continue" [ identifier ] .
-
-void
-Parse::continue_stat()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_CONTINUE));
- Location location = this->location();
-
- const Token* token = this->advance_token();
- Statement* enclosing;
- if (!token->is_identifier())
- {
- if (this->continue_stack_ == NULL || this->continue_stack_->empty())
- {
- error_at(this->location(), "continue statement not within for");
- return;
- }
- enclosing = this->continue_stack_->back().first;
- }
- else
- {
- enclosing = this->find_bc_statement(this->continue_stack_,
- token->identifier());
- if (enclosing == NULL)
- {
- // If there is a label with this name, mark it as used to
- // avoid a useless error about an unused label.
- this->gogo_->add_label_reference(token->identifier(),
- Linemap::unknown_location(), false);
-
- error_at(token->location(), "invalid continue label %qs",
- Gogo::message_name(token->identifier()).c_str());
- this->advance_token();
- return;
- }
- this->advance_token();
- }
-
- Unnamed_label* label;
- if (enclosing->classification() == Statement::STATEMENT_FOR)
- label = enclosing->for_statement()->continue_label();
- else if (enclosing->classification() == Statement::STATEMENT_FOR_RANGE)
- label = enclosing->for_range_statement()->continue_label();
- else
- go_unreachable();
-
- this->gogo_->add_statement(Statement::make_continue_statement(label,
- location));
-}
-
-// GotoStat = "goto" identifier .
-
-void
-Parse::goto_stat()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_GOTO));
- Location location = this->location();
- const Token* token = this->advance_token();
- if (!token->is_identifier())
- error_at(this->location(), "expected label for goto");
- else
- {
- Label* label = this->gogo_->add_label_reference(token->identifier(),
- location, true);
- Statement* s = Statement::make_goto_statement(label, location);
- this->gogo_->add_statement(s);
- this->advance_token();
- }
-}
-
-// PackageClause = "package" PackageName .
-
-void
-Parse::package_clause()
-{
- const Token* token = this->peek_token();
- Location location = token->location();
- std::string name;
- if (!token->is_keyword(KEYWORD_PACKAGE))
- {
- error_at(this->location(), "program must start with package clause");
- name = "ERROR";
- }
- else
- {
- token = this->advance_token();
- if (token->is_identifier())
- {
- name = token->identifier();
- if (name == "_")
- {
- error_at(this->location(), "invalid package name _");
- name = "blank";
- }
- this->advance_token();
- }
- else
- {
- error_at(this->location(), "package name must be an identifier");
- name = "ERROR";
- }
- }
- this->gogo_->set_package_name(name, location);
-}
-
-// ImportDecl = "import" Decl<ImportSpec> .
-
-void
-Parse::import_decl()
-{
- go_assert(this->peek_token()->is_keyword(KEYWORD_IMPORT));
- this->advance_token();
- this->decl(&Parse::import_spec, NULL);
-}
-
-// ImportSpec = [ "." | PackageName ] PackageFileName .
-
-void
-Parse::import_spec(void*)
-{
- const Token* token = this->peek_token();
- Location location = token->location();
-
- std::string local_name;
- bool is_local_name_exported = false;
- if (token->is_op(OPERATOR_DOT))
- {
- local_name = ".";
- token = this->advance_token();
- }
- else if (token->is_identifier())
- {
- local_name = token->identifier();
- is_local_name_exported = token->is_identifier_exported();
- token = this->advance_token();
- }
-
- if (!token->is_string())
- {
- error_at(this->location(), "import statement not a string");
- this->advance_token();
- return;
- }
-
- this->gogo_->import_package(token->string_value(), local_name,
- is_local_name_exported, location);
-
- this->advance_token();
-}
-
-// SourceFile = PackageClause ";" { ImportDecl ";" }
-// { TopLevelDecl ";" } .
-
-void
-Parse::program()
-{
- this->package_clause();
-
- const Token* token = this->peek_token();
- if (token->is_op(OPERATOR_SEMICOLON))
- token = this->advance_token();
- else
- error_at(this->location(),
- "expected %<;%> or newline after package clause");
-
- while (token->is_keyword(KEYWORD_IMPORT))
- {
- this->import_decl();
- token = this->peek_token();
- if (token->is_op(OPERATOR_SEMICOLON))
- token = this->advance_token();
- else
- error_at(this->location(),
- "expected %<;%> or newline after import declaration");
- }
-
- while (!token->is_eof())
- {
- if (this->declaration_may_start_here())
- this->declaration();
- else
- {
- error_at(this->location(), "expected declaration");
- this->gogo_->mark_locals_used();
- do
- this->advance_token();
- while (!this->peek_token()->is_eof()
- && !this->peek_token()->is_op(OPERATOR_SEMICOLON)
- && !this->peek_token()->is_op(OPERATOR_RCURLY));
- if (!this->peek_token()->is_eof()
- && !this->peek_token()->is_op(OPERATOR_SEMICOLON))
- this->advance_token();
- }
- token = this->peek_token();
- if (token->is_op(OPERATOR_SEMICOLON))
- token = this->advance_token();
- else if (!token->is_eof() || !saw_errors())
- {
- if (token->is_op(OPERATOR_CHANOP))
- error_at(this->location(),
- ("send statement used as value; "
- "use select for non-blocking send"));
- else
- error_at(this->location(),
- "expected %<;%> or newline after top level declaration");
- this->skip_past_error(OPERATOR_INVALID);
- }
- }
-}
-
-// Reset the current iota value.
-
-void
-Parse::reset_iota()
-{
- this->iota_ = 0;
-}
-
-// Return the current iota value.
-
-int
-Parse::iota_value()
-{
- return this->iota_;
-}
-
-// Increment the current iota value.
-
-void
-Parse::increment_iota()
-{
- ++this->iota_;
-}
-
-// Skip forward to a semicolon or OP. OP will normally be
-// OPERATOR_RPAREN or OPERATOR_RCURLY. If we find a semicolon, move
-// past it and return. If we find OP, it will be the next token to
-// read. Return true if we are OK, false if we found EOF.
-
-bool
-Parse::skip_past_error(Operator op)
-{
- this->gogo_->mark_locals_used();
- const Token* token = this->peek_token();
- while (!token->is_op(op))
- {
- if (token->is_eof())
- return false;
- if (token->is_op(OPERATOR_SEMICOLON))
- {
- this->advance_token();
- return true;
- }
- token = this->advance_token();
- }
- return true;
-}
-
-// Check that an expression is not a sink.
-
-Expression*
-Parse::verify_not_sink(Expression* expr)
-{
- if (expr->is_sink_expression())
- {
- error_at(expr->location(), "cannot use _ as value");
- expr = Expression::make_error(expr->location());
- }
- return expr;
-}
-
-// Mark a variable as used.
-
-void
-Parse::mark_var_used(Named_object* no)
-{
- if (no->is_variable())
- {
- no->var_value()->set_is_used();
-
- // When a type switch uses := to define a variable, then for
- // each case with a single type we introduce a new variable with
- // the appropriate type. When we do, if the newly introduced
- // variable is used, then the type switch variable is used.
- Type_switch_vars::iterator p = this->type_switch_vars_.find(no);
- if (p != this->type_switch_vars_.end())
- p->second->var_value()->set_is_used();
- }
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/parse.h b/gcc-4.8.1/gcc/go/gofrontend/parse.h
deleted file mode 100644
index 99e0eeebc..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/parse.h
+++ /dev/null
@@ -1,335 +0,0 @@
-// parse.h -- Go frontend parser. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_PARSE_H
-#define GO_PARSE_H
-
-class Set_iota_traverse;
-class Lex;
-class Gogo;
-class Named_object;
-class Type;
-class Typed_identifier;
-class Typed_identifier_list;
-class Channel_type;
-class Function_type;
-class Block;
-class Expression;
-class Expression_list;
-class Struct_field_list;
-class Case_clauses;
-class Type_case_clauses;
-class Select_clauses;
-class Statement;
-class Label;
-
-// Parse the program.
-
-class Parse
-{
- public:
- Parse(Lex*, Gogo*);
-
- // Parse a program.
- void
- program();
-
- private:
- // Precedence values.
- enum Precedence
- {
- PRECEDENCE_INVALID = -1,
- PRECEDENCE_NORMAL = 0,
- PRECEDENCE_OROR,
- PRECEDENCE_ANDAND,
- PRECEDENCE_RELOP,
- PRECEDENCE_ADDOP,
- PRECEDENCE_MULOP
- };
-
- // We use this when parsing the range clause of a for statement.
- struct Range_clause
- {
- // Set to true if we found a range clause.
- bool found;
- // The index expression.
- Expression* index;
- // The value expression.
- Expression* value;
- // The range expression.
- Expression* range;
-
- Range_clause()
- : found(false), index(NULL), value(NULL), range(NULL)
- { }
- };
-
- // We use this when parsing the statement at the start of a switch,
- // in order to recognize type switches.
- struct Type_switch
- {
- // Set to true if we find a type switch.
- bool found;
- // The variable name.
- std::string name;
- // The location of the variable.
- Location location;
- // The expression.
- Expression* expr;
-
- Type_switch()
- : found(false), name(), location(UNKNOWN_LOCATION), expr(NULL)
- { }
- };
-
- // A variable defined in an enclosing function referenced by the
- // current function.
- class Enclosing_var
- {
- public:
- Enclosing_var(Named_object* var, Named_object* in_function,
- unsigned int index)
- : var_(var), in_function_(in_function), index_(index)
- { }
-
- // We put these in a vector, so we need a default constructor.
- Enclosing_var()
- : var_(NULL), in_function_(NULL), index_(-1U)
- { }
-
- Named_object*
- var() const
- { return this->var_; }
-
- Named_object*
- in_function() const
- { return this->in_function_; }
-
- unsigned int
- index() const
- { return this->index_; }
-
- private:
- // The variable which is being referred to.
- Named_object* var_;
- // The function where the variable is defined.
- Named_object* in_function_;
- // The index of the field in this function's closure struct for
- // this variable.
- unsigned int index_;
- };
-
- // We store Enclosing_var entries in a set, so we need a comparator.
- struct Enclosing_var_comparison
- {
- bool
- operator()(const Enclosing_var&, const Enclosing_var&);
- };
-
- // A set of Enclosing_var entries.
- typedef std::set<Enclosing_var, Enclosing_var_comparison> Enclosing_vars;
-
- // Used to detect duplicate parameter/result names.
- typedef std::map<std::string, const Typed_identifier*> Names;
-
- // Peek at the current token from the lexer.
- const Token*
- peek_token();
-
- // Consume the current token, return the next one.
- const Token*
- advance_token();
-
- // Push a token back on the input stream.
- void
- unget_token(const Token&);
-
- // The location of the current token.
- Location
- location();
-
- // For break and continue we keep a stack of statements with
- // associated labels (if any). The top of the stack is used for a
- // break or continue statement with no label.
- typedef std::vector<std::pair<Statement*, Label*> > Bc_stack;
-
- // Map from type switch variables to the variables they mask, so
- // that a use of the type switch variable can become a use of the
- // real variable.
- typedef Unordered_map(Named_object*, Named_object*) Type_switch_vars;
-
- // Parser nonterminals.
- void identifier_list(Typed_identifier_list*);
- Expression_list* expression_list(Expression*, bool may_be_sink,
- bool may_be_composite_lit);
- bool qualified_ident(std::string*, Named_object**);
- Type* type();
- bool type_may_start_here();
- Type* type_name(bool issue_error);
- Type* array_type(bool may_use_ellipsis);
- Type* map_type();
- Type* struct_type();
- void field_decl(Struct_field_list*);
- Type* pointer_type();
- Type* channel_type();
- void check_signature_names(const Typed_identifier_list*, Names*);
- Function_type* signature(Typed_identifier*, Location);
- bool parameters(Typed_identifier_list**, bool* is_varargs);
- Typed_identifier_list* parameter_list(bool* is_varargs);
- void parameter_decl(bool, Typed_identifier_list*, bool*, bool*);
- bool result(Typed_identifier_list**);
- Location block();
- Type* interface_type();
- void method_spec(Typed_identifier_list*);
- void declaration();
- bool declaration_may_start_here();
- void decl(void (Parse::*)(void*), void*);
- void list(void (Parse::*)(void*), void*, bool);
- void const_decl();
- void const_spec(Type**, Expression_list**);
- void type_decl();
- void type_spec(void*);
- void var_decl();
- void var_spec(void*);
- void init_vars(const Typed_identifier_list*, Type*, Expression_list*,
- bool is_coloneq, Location);
- bool init_vars_from_call(const Typed_identifier_list*, Type*, Expression*,
- bool is_coloneq, Location);
- bool init_vars_from_map(const Typed_identifier_list*, Type*, Expression*,
- bool is_coloneq, Location);
- bool init_vars_from_receive(const Typed_identifier_list*, Type*,
- Expression*, bool is_coloneq, Location);
- bool init_vars_from_type_guard(const Typed_identifier_list*, Type*,
- Expression*, bool is_coloneq,
- Location);
- Named_object* init_var(const Typed_identifier&, Type*, Expression*,
- bool is_coloneq, bool type_from_init, bool* is_new,
- Expression_list* vars, Expression_list* vals);
- Named_object* create_dummy_global(Type*, Expression*, Location);
- void finish_init_vars(Expression_list* vars, Expression_list* vals,
- Location);
- void simple_var_decl_or_assignment(const std::string&, Location,
- bool may_be_composite_lit,
- Range_clause*, Type_switch*);
- void function_decl(bool saw_nointerface);
- Typed_identifier* receiver();
- Expression* operand(bool may_be_sink, bool *is_parenthesized);
- Expression* enclosing_var_reference(Named_object*, Named_object*,
- Location);
- Expression* composite_lit(Type*, int depth, Location);
- Expression* function_lit();
- Expression* create_closure(Named_object* function, Enclosing_vars*,
- Location);
- Expression* primary_expr(bool may_be_sink, bool may_be_composite_lit,
- bool* is_type_switch, bool* is_parenthesized);
- Expression* selector(Expression*, bool* is_type_switch);
- Expression* index(Expression*);
- Expression* call(Expression*);
- Expression* expression(Precedence, bool may_be_sink,
- bool may_be_composite_lit, bool* is_type_switch,
- bool *is_parenthesized);
- bool expression_may_start_here();
- Expression* unary_expr(bool may_be_sink, bool may_be_composite_lit,
- bool* is_type_switch, bool* is_parenthesized);
- Type* reassociate_chan_direction(Channel_type*, Location);
- Expression* qualified_expr(Expression*, Location);
- Expression* id_to_expression(const std::string&, Location);
- void statement(Label*);
- bool statement_may_start_here();
- void labeled_stmt(const std::string&, Location);
- Expression* simple_stat(bool, bool*, Range_clause*, Type_switch*);
- bool simple_stat_may_start_here();
- void statement_list();
- bool statement_list_may_start_here();
- void expression_stat(Expression*);
- void send_stmt(Expression*);
- void inc_dec_stat(Expression*);
- void assignment(Expression*, bool may_be_composite_lit, Range_clause*);
- void tuple_assignment(Expression_list*, bool may_be_composite_lit,
- Range_clause*);
- void send();
- void go_or_defer_stat();
- void return_stat();
- void if_stat();
- void switch_stat(Label*);
- Statement* expr_switch_body(Label*, Expression*, Location);
- void expr_case_clause(Case_clauses*, bool* saw_default);
- Expression_list* expr_switch_case(bool*);
- Statement* type_switch_body(Label*, const Type_switch&, Location);
- void type_case_clause(Named_object*, Type_case_clauses*, bool* saw_default);
- void type_switch_case(std::vector<Type*>*, bool*);
- void select_stat(Label*);
- void comm_clause(Select_clauses*, bool* saw_default);
- bool comm_case(bool*, Expression**, Expression**, Expression**,
- std::string*, std::string*, bool*);
- bool send_or_recv_stmt(bool*, Expression**, Expression**, Expression**,
- std::string*, std::string*);
- void for_stat(Label*);
- void for_clause(Expression**, Block**);
- void range_clause_decl(const Typed_identifier_list*, Range_clause*);
- void range_clause_expr(const Expression_list*, Range_clause*);
- void push_break_statement(Statement*, Label*);
- void push_continue_statement(Statement*, Label*);
- void pop_break_statement();
- void pop_continue_statement();
- Statement* find_bc_statement(const Bc_stack*, const std::string&);
- void break_stat();
- void continue_stat();
- void goto_stat();
- void package_clause();
- void import_decl();
- void import_spec(void*);
-
- void reset_iota();
- int iota_value();
- void increment_iota();
-
- // Skip past an error looking for a semicolon or OP. Return true if
- // all is well, false if we found EOF.
- bool
- skip_past_error(Operator op);
-
- // Verify that an expression is not a sink, and return either the
- // expression or an error.
- Expression*
- verify_not_sink(Expression*);
-
- // Return the statement associated with a label in a Bc_stack, or
- // NULL.
- Statement*
- find_bc_statement(const Bc_stack*, const std::string&) const;
-
- // Mark a variable as used.
- void
- mark_var_used(Named_object*);
-
- // The lexer output we are parsing.
- Lex* lex_;
- // The current token.
- Token token_;
- // A token pushed back on the input stream.
- Token unget_token_;
- // Whether unget_token_ is valid.
- bool unget_token_valid_;
- // Whether the function we are parsing had errors in the signature.
- bool is_erroneous_function_;
- // The code we are generating.
- Gogo* gogo_;
- // A stack of statements for which break may be used.
- Bc_stack* break_stack_;
- // A stack of statements for which continue may be used.
- Bc_stack* continue_stack_;
- // The current iota value.
- int iota_;
- // References from the local function to variables defined in
- // enclosing functions.
- Enclosing_vars enclosing_vars_;
- // Map from type switch variables to real variables.
- Type_switch_vars type_switch_vars_;
-};
-
-
-#endif // !defined(GO_PARSE_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/runtime.cc b/gcc-4.8.1/gcc/go/gofrontend/runtime.cc
deleted file mode 100644
index ecc508d0d..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/runtime.cc
+++ /dev/null
@@ -1,402 +0,0 @@
-// runtime.cc -- runtime functions called by generated code
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "gogo.h"
-#include "types.h"
-#include "expressions.h"
-#include "runtime.h"
-
-// The frontend generates calls to various runtime functions. They
-// are implemented in libgo/runtime. This is how the runtime
-// functions are represented in the frontend. Note that there is
-// currently nothing which ensures that the compiler's understanding
-// of the runtime function matches the actual implementation in
-// libgo/runtime.
-
-// Parameter and result types used by runtime functions.
-
-enum Runtime_function_type
-{
- // General indicator that value is not used.
- RFT_VOID,
- // Go type bool, C type _Bool.
- RFT_BOOL,
- // Go type *bool, C type _Bool*.
- RFT_BOOLPTR,
- // Go type int, C type intgo.
- RFT_INT,
- // Go type int32, C type int32_t.
- RFT_INT32,
- // Go type int64, C type int64_t.
- RFT_INT64,
- // Go type uint64, C type uint64_t.
- RFT_UINT64,
- // Go type uintptr, C type uintptr_t.
- RFT_UINTPTR,
- // Go type rune, C type int32_t.
- RFT_RUNE,
- // Go type float64, C type double.
- RFT_FLOAT64,
- // Go type complex128, C type __complex double.
- RFT_COMPLEX128,
- // Go type string, C type struct __go_string.
- RFT_STRING,
- // Go type unsafe.Pointer, C type "void *".
- RFT_POINTER,
- // Go type []any, C type struct __go_open_array.
- RFT_SLICE,
- // Go type map[any]any, C type struct __go_map *.
- RFT_MAP,
- // Pointer to map iteration type.
- RFT_MAPITER,
- // Go type chan any, C type struct __go_channel *.
- RFT_CHAN,
- // Go type non-empty interface, C type struct __go_interface.
- RFT_IFACE,
- // Go type interface{}, C type struct __go_empty_interface.
- RFT_EFACE,
- // Go type func(unsafe.Pointer), C type void (*) (void *).
- RFT_FUNC_PTR,
- // Pointer to Go type descriptor.
- RFT_TYPE,
- // Pointer to map descriptor.
- RFT_MAPDESCRIPTOR,
-
- NUMBER_OF_RUNTIME_FUNCTION_TYPES
-};
-
-// The Type structures for the runtime function types.
-
-static Type* runtime_function_types[NUMBER_OF_RUNTIME_FUNCTION_TYPES];
-
-// Get the Type for a Runtime_function_type code.
-
-static Type*
-runtime_function_type(Runtime_function_type bft)
-{
- go_assert(bft < NUMBER_OF_RUNTIME_FUNCTION_TYPES);
- if (runtime_function_types[bft] == NULL)
- {
- const Location bloc = Linemap::predeclared_location();
- Type* t;
- switch (bft)
- {
- default:
- case RFT_VOID:
- go_unreachable();
-
- case RFT_BOOL:
- t = Type::lookup_bool_type();
- break;
-
- case RFT_BOOLPTR:
- t = Type::make_pointer_type(Type::lookup_bool_type());
- break;
-
- case RFT_INT:
- t = Type::lookup_integer_type("int");
- break;
-
- case RFT_INT32:
- t = Type::lookup_integer_type("int32");
- break;
-
- case RFT_INT64:
- t = Type::lookup_integer_type("int64");
- break;
-
- case RFT_UINT64:
- t = Type::lookup_integer_type("uint64");
- break;
-
- case RFT_RUNE:
- t = Type::lookup_integer_type("int32");
- break;
-
- case RFT_UINTPTR:
- t = Type::lookup_integer_type("uintptr");
- break;
-
- case RFT_FLOAT64:
- t = Type::lookup_float_type("float64");
- break;
-
- case RFT_COMPLEX128:
- t = Type::lookup_complex_type("complex128");
- break;
-
- case RFT_STRING:
- t = Type::lookup_string_type();
- break;
-
- case RFT_POINTER:
- t = Type::make_pointer_type(Type::make_void_type());
- break;
-
- case RFT_SLICE:
- t = Type::make_array_type(Type::make_void_type(), NULL);
- break;
-
- case RFT_MAP:
- t = Type::make_map_type(Type::make_void_type(),
- Type::make_void_type(),
- bloc);
- break;
-
- case RFT_MAPITER:
- t = Type::make_pointer_type(Runtime::map_iteration_type());
- break;
-
- case RFT_CHAN:
- t = Type::make_channel_type(true, true, Type::make_void_type());
- break;
-
- case RFT_IFACE:
- {
- Typed_identifier_list* methods = new Typed_identifier_list();
- Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc);
- methods->push_back(Typed_identifier("x", mtype, bloc));
- Interface_type* it = Type::make_interface_type(methods, bloc);
- it->finalize_methods();
- t = it;
- }
- break;
-
- case RFT_EFACE:
- t = Type::make_empty_interface_type(bloc);
- break;
-
- case RFT_FUNC_PTR:
- {
- Typed_identifier_list* param_types = new Typed_identifier_list();
- Type* ptrtype = runtime_function_type(RFT_POINTER);
- param_types->push_back(Typed_identifier("", ptrtype, bloc));
- t = Type::make_function_type(NULL, param_types, NULL, bloc);
- }
- break;
-
- case RFT_TYPE:
- t = Type::make_type_descriptor_ptr_type();
- break;
-
- case RFT_MAPDESCRIPTOR:
- t = Type::make_pointer_type(Map_type::make_map_descriptor_type());
- break;
- }
-
- runtime_function_types[bft] = t;
- }
-
- return runtime_function_types[bft];
-}
-
-// Convert an expression to the type to pass to a runtime function.
-
-static Expression*
-convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
- Location loc)
-{
- switch (bft)
- {
- default:
- case RFT_VOID:
- go_unreachable();
-
- case RFT_BOOL:
- case RFT_BOOLPTR:
- case RFT_INT:
- case RFT_INT32:
- case RFT_INT64:
- case RFT_UINT64:
- case RFT_UINTPTR:
- case RFT_RUNE:
- case RFT_FLOAT64:
- case RFT_COMPLEX128:
- case RFT_STRING:
- case RFT_POINTER:
- case RFT_MAPITER:
- case RFT_FUNC_PTR:
- {
- Type* t = runtime_function_type(bft);
- if (!Type::are_identical(t, e->type(), true, NULL))
- e = Expression::make_cast(t, e, loc);
- return e;
- }
-
- case RFT_SLICE:
- case RFT_MAP:
- case RFT_CHAN:
- case RFT_IFACE:
- case RFT_EFACE:
- return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc);
-
- case RFT_TYPE:
- go_assert(e->type() == Type::make_type_descriptor_ptr_type());
- return e;
-
- case RFT_MAPDESCRIPTOR:
- go_assert(e->type()->points_to()
- == Map_type::make_map_descriptor_type());
- return e;
- }
-}
-
-// Convert all the types used for runtime functions to the backend
-// representation.
-
-void
-Runtime::convert_types(Gogo* gogo)
-{
- for (int i = 0; i < static_cast<int>(NUMBER_OF_RUNTIME_FUNCTION_TYPES); ++i)
- {
- Type* t = runtime_function_types[i];
- if (t != NULL && t->named_type() != NULL)
- {
- bool r = t->verify();
- go_assert(r);
- t->named_type()->convert(gogo);
- }
- }
-}
-
-// The type used to define a runtime function.
-
-struct Runtime_function
-{
- // Function name.
- const char* name;
- // Parameter types. Never more than 6, as it happens. RFT_VOID if
- // not used.
- Runtime_function_type parameter_types[6];
- // Result types. Never more than 2, as it happens. RFT_VOID if not
- // used.
- Runtime_function_type result_types[2];
-};
-
-static const Runtime_function runtime_functions[] =
-{
-
-#define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) { NAME, PARAMS, RESULTS } ,
-
-#include "runtime.def"
-
-#undef DEF_GO_RUNTIME
-
-};
-
-static Named_object*
-runtime_function_declarations[Runtime::NUMBER_OF_FUNCTIONS];
-
-// Get the declaration of a runtime function.
-
-Named_object*
-Runtime::runtime_declaration(Function code)
-{
- go_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
- if (runtime_function_declarations[code] == NULL)
- {
- const Runtime_function* pb = &runtime_functions[code];
-
- Location bloc = Linemap::predeclared_location();
-
- Typed_identifier_list* param_types = NULL;
- if (pb->parameter_types[0] != RFT_VOID)
- {
- param_types = new Typed_identifier_list();
- for (unsigned int i = 0;
- i < (sizeof(pb->parameter_types)
- / sizeof (pb->parameter_types[0]));
- i++)
- {
- if (pb->parameter_types[i] == RFT_VOID)
- break;
- Type* t = runtime_function_type(pb->parameter_types[i]);
- param_types->push_back(Typed_identifier("", t, bloc));
- }
- }
-
- Typed_identifier_list* result_types = NULL;
- if (pb->result_types[0] != RFT_VOID)
- {
- result_types = new Typed_identifier_list();
- for (unsigned int i = 0;
- i < sizeof(pb->result_types) / sizeof(pb->result_types[0]);
- i++)
- {
- if (pb->result_types[i] == RFT_VOID)
- break;
- Type* t = runtime_function_type(pb->result_types[i]);
- result_types->push_back(Typed_identifier("", t, bloc));
- }
- }
-
- Function_type* fntype = Type::make_function_type(NULL, param_types,
- result_types, bloc);
- const char* n = pb->name;
- const char* n1 = strchr(n, '.');
- if (n1 != NULL)
- n = n1 + 1;
- Named_object* no = Named_object::make_function_declaration(n, NULL,
- fntype, bloc);
- no->func_declaration_value()->set_asm_name(pb->name);
-
- runtime_function_declarations[code] = no;
- }
-
- return runtime_function_declarations[code];
-}
-
-// Make a call to a runtime function.
-
-Call_expression*
-Runtime::make_call(Runtime::Function code, Location loc,
- int param_count, ...)
-{
- go_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
-
- const Runtime_function* pb = &runtime_functions[code];
-
- go_assert(static_cast<size_t>(param_count)
- <= sizeof(pb->parameter_types) / sizeof(pb->parameter_types[0]));
-
- Named_object* no = runtime_declaration(code);
- Expression* func = Expression::make_func_reference(no, NULL, loc);
-
- Expression_list* args = new Expression_list();
- args->reserve(param_count);
-
- va_list ap;
- va_start(ap, param_count);
- for (int i = 0; i < param_count; ++i)
- {
- Expression* e = va_arg(ap, Expression*);
- Runtime_function_type rft = pb->parameter_types[i];
- args->push_back(convert_to_runtime_function_type(rft, e, loc));
- }
- va_end(ap);
-
- return Expression::make_call(func, args, false, loc);
-}
-
-// The type we use for a map iteration. This is really a struct which
-// is four pointers long. This must match the runtime struct
-// __go_hash_iter.
-
-Type*
-Runtime::map_iteration_type()
-{
- const unsigned long map_iteration_size = 4;
-
- mpz_t ival;
- mpz_init_set_ui(ival, map_iteration_size);
- Expression* iexpr = Expression::make_integer(&ival, NULL,
- Linemap::predeclared_location());
- mpz_clear(ival);
-
- return Type::make_array_type(runtime_function_type(RFT_POINTER), iexpr);
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/runtime.def b/gcc-4.8.1/gcc/go/gofrontend/runtime.def
deleted file mode 100644
index 0d9ff0380..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/runtime.def
+++ /dev/null
@@ -1,373 +0,0 @@
-// runtime.def -- runtime functions called by generated code. -*- C++ -*-
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Definitions for the Go runtime functions.
-
-// Parameter type helper macros.
-#define ABFT6(T1, T2, T3, T4, T5, T6) \
- { RFT_ ## T1, RFT_ ## T2, RFT_ ## T3, RFT_ ## T4, RFT_ ## T5, RFT_ ## T6 }
-#define P0() ABFT6(VOID, VOID, VOID, VOID, VOID, VOID)
-#define P1(T) ABFT6(T, VOID, VOID, VOID, VOID, VOID)
-#define P2(T1, T2) ABFT6(T1, T2, VOID, VOID, VOID, VOID)
-#define P3(T1, T2, T3) ABFT6(T1, T2, T3, VOID, VOID, VOID)
-#define P4(T1, T2, T3, T4) ABFT6(T1, T2, T3, T4, VOID, VOID)
-#define P5(T1, T2, T3, T4, T5) ABFT6(T1, T2, T3, T4, T5, VOID)
-#define P6(T1,T2,T3,T4,T5,T6) ABFT6(T1, T2, T3, T4, T5, T6)
-
-// Result type helper macros.
-#define ABFT2(T1, T2) { RFT_ ## T1, RFT_ ## T2 }
-#define R0() ABFT2(VOID, VOID)
-#define R1(T) ABFT2(T, VOID)
-#define R2(T1, T2) ABFT2(T1, T2)
-
-// Define all the Go runtime functions. The first parameter is the
-// enum code used to refer to the function. The second parameter is
-// the name. The third is the parameter types and the fourth is the
-// result types.
-
-// The standard C memcmp function, used for struct comparisons.
-DEF_GO_RUNTIME(MEMCMP, "__go_memcmp", P3(POINTER, POINTER, UINTPTR), R1(INT))
-
-// Range over a string, returning the next index.
-DEF_GO_RUNTIME(STRINGITER, "runtime.stringiter", P2(STRING, INT), R1(INT))
-
-// Range over a string, returning the next index and character.
-DEF_GO_RUNTIME(STRINGITER2, "runtime.stringiter2", P2(STRING, INT),
- R2(INT, RUNE))
-
-// Concatenate two strings.
-DEF_GO_RUNTIME(STRING_PLUS, "__go_string_plus", P2(STRING, STRING), R1(STRING))
-
-// Compare two strings.
-DEF_GO_RUNTIME(STRCMP, "__go_strcmp", P2(STRING, STRING), R1(INT))
-
-// Take a slice of a string.
-DEF_GO_RUNTIME(STRING_SLICE, "__go_string_slice", P3(STRING, INT, INT),
- R1(STRING))
-
-// Convert an integer to a string.
-DEF_GO_RUNTIME(INT_TO_STRING, "__go_int_to_string", P1(INT), R1(STRING))
-
-// Convert a byte array to a string.
-DEF_GO_RUNTIME(BYTE_ARRAY_TO_STRING, "__go_byte_array_to_string",
- P2(POINTER, INT), R1(STRING))
-
-// Convert an int array to a string.
-DEF_GO_RUNTIME(INT_ARRAY_TO_STRING, "__go_int_array_to_string",
- P2(POINTER, INT), R1(STRING))
-
-// Convert a string to a byte slice.
-DEF_GO_RUNTIME(STRING_TO_BYTE_ARRAY, "__go_string_to_byte_array",
- P1(STRING), R1(SLICE))
-
-// Convert a string to an int slice.
-DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__go_string_to_int_array",
- P1(STRING), R1(SLICE))
-
-
-// Make a slice.
-DEF_GO_RUNTIME(MAKESLICE1, "__go_make_slice1", P2(TYPE, UINTPTR), R1(SLICE))
-DEF_GO_RUNTIME(MAKESLICE2, "__go_make_slice2", P3(TYPE, UINTPTR, UINTPTR),
- R1(SLICE))
-DEF_GO_RUNTIME(MAKESLICE1BIG, "__go_make_slice1_big", P2(TYPE, UINT64),
- R1(SLICE))
-DEF_GO_RUNTIME(MAKESLICE2BIG, "__go_make_slice2_big", P3(TYPE, UINT64, UINT64),
- R1(SLICE))
-
-
-// Make a map.
-DEF_GO_RUNTIME(MAKEMAP, "__go_new_map", P2(MAPDESCRIPTOR, UINTPTR), R1(MAP))
-DEF_GO_RUNTIME(MAKEMAPBIG, "__go_new_map_big", P2(MAPDESCRIPTOR, UINT64),
- R1(MAP))
-
-// Build a map from a composite literal.
-DEF_GO_RUNTIME(CONSTRUCT_MAP, "__go_construct_map",
- P6(POINTER, UINTPTR, UINTPTR, UINTPTR, UINTPTR, POINTER),
- R1(MAP))
-
-// Get the length of a map (the number of entries).
-DEF_GO_RUNTIME(MAP_LEN, "__go_map_len", P1(MAP), R1(INT))
-
-// Look up a key in a map.
-DEF_GO_RUNTIME(MAP_INDEX, "__go_map_index", P3(MAP, POINTER, BOOL),
- R1(POINTER))
-
-// Look up a key in a map returning whether it is present.
-DEF_GO_RUNTIME(MAPACCESS2, "runtime.mapaccess2",
- P4(TYPE, MAP, POINTER, POINTER), R1(BOOL))
-
-// Tuple assignment to a map element.
-DEF_GO_RUNTIME(MAPASSIGN2, "runtime.mapassign2",
- P4(MAP, POINTER, POINTER, BOOL), R0())
-
-// Delete a key from a map.
-DEF_GO_RUNTIME(MAPDELETE, "runtime.mapdelete", P2(MAP, POINTER), R0())
-
-// Begin a range over a map.
-DEF_GO_RUNTIME(MAPITERINIT, "runtime.mapiterinit", P2(MAP, MAPITER), R0())
-
-// Range over a map, returning the next key.
-DEF_GO_RUNTIME(MAPITER1, "runtime.mapiter1", P2(MAPITER, POINTER), R0())
-
-// Range over a map, returning the next key and value.
-DEF_GO_RUNTIME(MAPITER2, "runtime.mapiter2", P3(MAPITER, POINTER, POINTER),
- R0())
-
-// Range over a map, moving to the next map entry.
-DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(MAPITER), R0())
-
-
-// Make a channel.
-DEF_GO_RUNTIME(MAKECHAN, "__go_new_channel", P2(TYPE, UINTPTR), R1(CHAN))
-DEF_GO_RUNTIME(MAKECHANBIG, "__go_new_channel_big", P2(TYPE, UINT64), R1(CHAN))
-
-// Get the length of a channel (the number of unread values).
-DEF_GO_RUNTIME(CHAN_LEN, "__go_chan_len", P1(CHAN), R1(INT))
-
-// Get the capacity of a channel (the size of the buffer).
-DEF_GO_RUNTIME(CHAN_CAP, "__go_chan_cap", P1(CHAN), R1(INT))
-
-// Send a small value on a channel.
-DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(TYPE, CHAN, UINT64), R0())
-
-// Send a big value on a channel.
-DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(TYPE, CHAN, POINTER), R0())
-
-// Receive a small value from a channel.
-DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(TYPE, CHAN), R1(UINT64))
-
-// Receive a big value from a channel.
-DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(TYPE, CHAN, POINTER), R0())
-
-// Receive a value from a channel returning whether it is closed.
-DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER),
- R1(BOOL))
-
-
-// Start building a select statement.
-DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P1(INT32), R1(POINTER))
-
-// Add a default clause to a select statement.
-DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault",
- P2(POINTER, INT32), R0())
-
-// Add a send clause to a select statement.
-DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend",
- P4(POINTER, CHAN, POINTER, INT32), R0())
-
-// Add a receive clause to a select statement, for a clause which does
-// not check whether the channel is closed.
-DEF_GO_RUNTIME(SELECTRECV, "runtime.selectrecv",
- P4(POINTER, CHAN, POINTER, INT32), R0())
-
-// Add a receive clause to a select statement, for a clause which does
-// check whether the channel is closed.
-DEF_GO_RUNTIME(SELECTRECV2, "runtime.selectrecv2",
- P5(POINTER, CHAN, POINTER, BOOLPTR, INT32), R0())
-
-// Run a select, returning the index of the selected clause.
-DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P1(POINTER), R1(INT32))
-
-
-// Panic.
-DEF_GO_RUNTIME(PANIC, "__go_panic", P1(EFACE), R0())
-
-// Recover.
-DEF_GO_RUNTIME(RECOVER, "__go_recover", P0(), R1(EFACE))
-
-// Recover when called directly from defer.
-DEF_GO_RUNTIME(DEFERRED_RECOVER, "__go_deferred_recover", P0(), R1(EFACE))
-
-// Decide whether this function can call recover.
-DEF_GO_RUNTIME(CAN_RECOVER, "__go_can_recover", P1(POINTER), R1(BOOL))
-
-// Get the return address of the function.
-DEF_GO_RUNTIME(RETURN_ADDRESS, "__go_return_address", P1(INT), R1(POINTER))
-
-// Set the return address for defer in a defer thunk.
-DEF_GO_RUNTIME(SET_DEFER_RETADDR, "__go_set_defer_retaddr", P1(POINTER),
- R1(BOOL))
-
-// Check for a deferred function in an exception handler.
-DEF_GO_RUNTIME(CHECK_DEFER, "__go_check_defer", P1(BOOLPTR), R0())
-
-// Run deferred functions.
-DEF_GO_RUNTIME(UNDEFER, "__go_undefer", P1(BOOLPTR), R0())
-
-// Panic with a runtime error.
-DEF_GO_RUNTIME(RUNTIME_ERROR, "__go_runtime_error", P1(INT32), R0())
-
-
-// Close.
-DEF_GO_RUNTIME(CLOSE, "__go_close", P1(CHAN), R0())
-
-
-// Copy.
-DEF_GO_RUNTIME(COPY, "__go_copy", P3(POINTER, POINTER, UINTPTR), R0())
-
-// Append.
-DEF_GO_RUNTIME(APPEND, "__go_append", P4(SLICE, POINTER, UINTPTR, UINTPTR),
- R1(SLICE))
-
-
-// Register roots (global variables) for the garbage collector.
-DEF_GO_RUNTIME(REGISTER_GC_ROOTS, "__go_register_gc_roots", P1(POINTER), R0())
-
-
-// Allocate memory.
-DEF_GO_RUNTIME(NEW, "__go_new", P1(UINTPTR), R1(POINTER))
-
-// Allocate memory which can not contain pointers.
-DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P1(UINTPTR), R1(POINTER))
-
-
-// Allocate a trampoline for a function literal.
-DEF_GO_RUNTIME(ALLOCATE_GO_TRAMPOLINE, "__go_allocate_trampoline",
- P2(UINTPTR, POINTER), R1(POINTER))
-
-
-// Start a new goroutine.
-DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0())
-
-
-// Defer a function.
-DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0())
-
-
-// Convert an empty interface to an empty interface, returning ok.
-DEF_GO_RUNTIME(IFACEE2E2, "runtime.ifaceE2E2", P1(EFACE), R2(EFACE, BOOL))
-
-// Convert a non-empty interface to an empty interface, returning ok.
-DEF_GO_RUNTIME(IFACEI2E2, "runtime.ifaceI2E2", P1(IFACE), R2(EFACE, BOOL))
-
-// Convert an empty interface to a non-empty interface, returning ok.
-DEF_GO_RUNTIME(IFACEE2I2, "runtime.ifaceE2I2", P2(TYPE, EFACE),
- R2(IFACE, BOOL))
-
-// Convert a non-empty interface to a non-empty interface, returning ok.
-DEF_GO_RUNTIME(IFACEI2I2, "runtime.ifaceI2I2", P2(TYPE, IFACE),
- R2(IFACE, BOOL))
-
-// Convert an empty interface to a pointer type, returning ok.
-DEF_GO_RUNTIME(IFACEE2T2P, "runtime.ifaceE2T2P", P2(TYPE, EFACE),
- R2(POINTER, BOOL))
-
-// Convert a non-empty interface to a pointer type, return ok.
-DEF_GO_RUNTIME(IFACEI2T2P, "runtime.ifaceI2T2P", P2(TYPE, IFACE),
- R2(POINTER, BOOL))
-
-// Convert an empty interface to a non-pointer type, returning ok.
-DEF_GO_RUNTIME(IFACEE2T2, "runtime.ifaceE2T2", P3(TYPE, EFACE, POINTER),
- R1(BOOL))
-
-// Convert a non-empty interface to a non-pointer type, returning ok.
-DEF_GO_RUNTIME(IFACEI2T2, "runtime.ifaceI2T2", P3(TYPE, IFACE, POINTER),
- R1(BOOL))
-
-// A type assertion from one interface type to another. This is
-// used for a type assertion.
-DEF_GO_RUNTIME(ASSERT_INTERFACE, "__go_assert_interface", P2(TYPE, TYPE), R0())
-
-// Convert one interface type to another. This is used for an
-// assignment.
-DEF_GO_RUNTIME(CONVERT_INTERFACE, "__go_convert_interface", P2(TYPE, TYPE),
- R1(POINTER))
-
-// Check whether an interface type may be converted to a
-// non-interface type.
-DEF_GO_RUNTIME(CHECK_INTERFACE_TYPE, "__go_check_interface_type",
- P3(TYPE, TYPE, TYPE), R0())
-
-// Return whether we can convert an interface type to a type.
-DEF_GO_RUNTIME(IFACEI2TP, "runtime.ifaceI2Tp", P2(TYPE, TYPE), R1(BOOL))
-
-// Get the type descriptor of an empty interface.
-DEF_GO_RUNTIME(EFACETYPE, "runtime.efacetype", P1(EFACE), R1(TYPE))
-
-// Get the type descriptor of a non-empty interface.
-DEF_GO_RUNTIME(IFACETYPE, "runtime.ifacetype", P1(IFACE), R1(TYPE))
-
-
-// Compare two type descriptors for equality.
-DEF_GO_RUNTIME(IFACETYPEEQ, "runtime.ifacetypeeq", P2(TYPE, TYPE), R1(BOOL))
-
-// Compare two empty interface values.
-DEF_GO_RUNTIME(EMPTY_INTERFACE_COMPARE, "__go_empty_interface_compare",
- P2(EFACE, EFACE), R1(INT))
-
-// Compare an empty interface value to a non-interface value.
-DEF_GO_RUNTIME(EMPTY_INTERFACE_VALUE_COMPARE,
- "__go_empty_interface_value_compare",
- P3(EFACE, TYPE, POINTER), R1(INT))
-
-// Compare two non-empty interface values.
-DEF_GO_RUNTIME(INTERFACE_COMPARE, "__go_interface_compare",
- P2(IFACE, IFACE), R1(INT))
-
-// Compare a non-empty interface value to a non-interface value.
-DEF_GO_RUNTIME(INTERFACE_VALUE_COMPARE, "__go_interface_value_compare",
- P3(IFACE, TYPE, POINTER), R1(INT))
-
-// Compare a non-empty interface value to an interface value.
-DEF_GO_RUNTIME(INTERFACE_EMPTY_COMPARE, "__go_interface_empty_compare",
- P2(IFACE, EFACE), R1(INT))
-
-
-// Print a string (for print/println).
-DEF_GO_RUNTIME(PRINT_STRING, "__go_print_string", P1(STRING), R0())
-
-// Print a uint64 (for print/println).
-DEF_GO_RUNTIME(PRINT_UINT64, "__go_print_uint64", P1(UINT64), R0())
-
-// Print a int64 (for print/println).
-DEF_GO_RUNTIME(PRINT_INT64, "__go_print_int64", P1(INT64), R0())
-
-// Print a float64 (for print/println).
-DEF_GO_RUNTIME(PRINT_DOUBLE, "__go_print_double", P1(FLOAT64), R0())
-
-// Print a complex128 (for print/println).
-DEF_GO_RUNTIME(PRINT_COMPLEX, "__go_print_complex", P1(COMPLEX128), R0())
-
-// Print a bool (for print/println).
-DEF_GO_RUNTIME(PRINT_BOOL, "__go_print_bool", P1(BOOL), R0())
-
-// Print a pointer/map/channel/function (for print/println).
-DEF_GO_RUNTIME(PRINT_POINTER, "__go_print_pointer", P1(POINTER), R0())
-
-// Print an empty interface (for print/println).
-DEF_GO_RUNTIME(PRINT_EMPTY_INTERFACE, "__go_print_empty_interface",
- P1(EFACE), R0())
-
-// Print a non-empty interface (for print/println).
-DEF_GO_RUNTIME(PRINT_INTERFACE, "__go_print_interface", P1(IFACE), R0())
-
-// Print a slice (for print/println).
-DEF_GO_RUNTIME(PRINT_SLICE, "__go_print_slice", P1(SLICE), R0())
-
-// Print a space (for println).
-DEF_GO_RUNTIME(PRINT_SPACE, "__go_print_space", P0(), R0())
-
-// Print a newline (for println).
-DEF_GO_RUNTIME(PRINT_NL, "__go_print_nl", P0(), R0())
-
-
-// Used for field tracking for data analysis.
-DEF_GO_RUNTIME(FIELDTRACK, "__go_fieldtrack", P1(POINTER), R0())
-
-
-// Remove helper macros.
-#undef ABFT6
-#undef ABFT2
-#undef P0
-#undef P1
-#undef P2
-#undef P3
-#undef P4
-#undef P5
-#undef P6
-#undef R0
-#undef R1
-#undef R2
diff --git a/gcc-4.8.1/gcc/go/gofrontend/runtime.h b/gcc-4.8.1/gcc/go/gofrontend/runtime.h
deleted file mode 100644
index be5dcbe25..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/runtime.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// runtime.h -- runtime functions called by generated code -*- C++ -*-
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_RUNTIME_H
-#define GO_RUNTIME_H
-
-class Gogo;
-class Type;
-class Named_object;
-class Call_expression;
-
-class Runtime
-{
- public:
-
- // The runtime functions which may be called by generated code.
- enum Function
- {
-
-#define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) CODE ,
-
-#include "runtime.def"
-
-#undef DEF_GO_RUNTIME
-
- // Number of runtime functions.
- NUMBER_OF_FUNCTIONS
- };
-
- // Make a call to a runtime function.
- static Call_expression*
- make_call(Function, Location, int, ...);
-
- // Convert all the types used by runtime functions to the backend
- // representation.
- static void
- convert_types(Gogo*);
-
- // Return the type used for iterations over maps.
- static Type*
- map_iteration_type();
-
- private:
- static Named_object*
- runtime_declaration(Function);
-};
-
-#endif // !defined(GO_BUILTINS_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/statements.cc b/gcc-4.8.1/gcc/go/gofrontend/statements.cc
deleted file mode 100644
index 7870dad72..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/statements.cc
+++ /dev/null
@@ -1,5918 +0,0 @@
-// statements.cc -- Go frontend statements.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "go-c.h"
-#include "types.h"
-#include "expressions.h"
-#include "gogo.h"
-#include "runtime.h"
-#include "backend.h"
-#include "statements.h"
-#include "ast-dump.h"
-
-// Class Statement.
-
-Statement::Statement(Statement_classification classification,
- Location location)
- : classification_(classification), location_(location)
-{
-}
-
-Statement::~Statement()
-{
-}
-
-// Traverse the tree. The work of walking the components is handled
-// by the subclasses.
-
-int
-Statement::traverse(Block* block, size_t* pindex, Traverse* traverse)
-{
- if (this->classification_ == STATEMENT_ERROR)
- return TRAVERSE_CONTINUE;
-
- unsigned int traverse_mask = traverse->traverse_mask();
-
- if ((traverse_mask & Traverse::traverse_statements) != 0)
- {
- int t = traverse->statement(block, pindex, this);
- if (t == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- else if (t == TRAVERSE_SKIP_COMPONENTS)
- return TRAVERSE_CONTINUE;
- }
-
- // No point in checking traverse_mask here--a statement may contain
- // other blocks or statements, and if we got here we always want to
- // walk them.
- return this->do_traverse(traverse);
-}
-
-// Traverse the contents of a statement.
-
-int
-Statement::traverse_contents(Traverse* traverse)
-{
- return this->do_traverse(traverse);
-}
-
-// Traverse assignments.
-
-bool
-Statement::traverse_assignments(Traverse_assignments* tassign)
-{
- if (this->classification_ == STATEMENT_ERROR)
- return false;
- return this->do_traverse_assignments(tassign);
-}
-
-// Traverse an expression in a statement. This is a helper function
-// for child classes.
-
-int
-Statement::traverse_expression(Traverse* traverse, Expression** expr)
-{
- if ((traverse->traverse_mask()
- & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
- return TRAVERSE_CONTINUE;
- return Expression::traverse(expr, traverse);
-}
-
-// Traverse an expression list in a statement. This is a helper
-// function for child classes.
-
-int
-Statement::traverse_expression_list(Traverse* traverse,
- Expression_list* expr_list)
-{
- if (expr_list == NULL)
- return TRAVERSE_CONTINUE;
- if ((traverse->traverse_mask()
- & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
- return TRAVERSE_CONTINUE;
- return expr_list->traverse(traverse);
-}
-
-// Traverse a type in a statement. This is a helper function for
-// child classes.
-
-int
-Statement::traverse_type(Traverse* traverse, Type* type)
-{
- if ((traverse->traverse_mask()
- & (Traverse::traverse_types | Traverse::traverse_expressions)) == 0)
- return TRAVERSE_CONTINUE;
- return Type::traverse(type, traverse);
-}
-
-// Set type information for unnamed constants. This is really done by
-// the child class.
-
-void
-Statement::determine_types()
-{
- this->do_determine_types();
-}
-
-// If this is a thunk statement, return it.
-
-Thunk_statement*
-Statement::thunk_statement()
-{
- Thunk_statement* ret = this->convert<Thunk_statement, STATEMENT_GO>();
- if (ret == NULL)
- ret = this->convert<Thunk_statement, STATEMENT_DEFER>();
- return ret;
-}
-
-// Convert a Statement to the backend representation. This is really
-// done by the child class.
-
-Bstatement*
-Statement::get_backend(Translate_context* context)
-{
- if (this->classification_ == STATEMENT_ERROR)
- return context->backend()->error_statement();
- return this->do_get_backend(context);
-}
-
-// Dump AST representation for a statement to a dump context.
-
-void
-Statement::dump_statement(Ast_dump_context* ast_dump_context) const
-{
- this->do_dump_statement(ast_dump_context);
-}
-
-// Note that this statement is erroneous. This is called by children
-// when they discover an error.
-
-void
-Statement::set_is_error()
-{
- this->classification_ = STATEMENT_ERROR;
-}
-
-// For children to call to report an error conveniently.
-
-void
-Statement::report_error(const char* msg)
-{
- error_at(this->location_, "%s", msg);
- this->set_is_error();
-}
-
-// An error statement, used to avoid crashing after we report an
-// error.
-
-class Error_statement : public Statement
-{
- public:
- Error_statement(Location location)
- : Statement(STATEMENT_ERROR, location)
- { }
-
- protected:
- int
- do_traverse(Traverse*)
- { return TRAVERSE_CONTINUE; }
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-};
-
-// Dump the AST representation for an error statement.
-
-void
-Error_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "Error statement" << std::endl;
-}
-
-// Make an error statement.
-
-Statement*
-Statement::make_error_statement(Location location)
-{
- return new Error_statement(location);
-}
-
-// Class Variable_declaration_statement.
-
-Variable_declaration_statement::Variable_declaration_statement(
- Named_object* var)
- : Statement(STATEMENT_VARIABLE_DECLARATION, var->var_value()->location()),
- var_(var)
-{
-}
-
-// We don't actually traverse the variable here; it was traversed
-// while traversing the Block.
-
-int
-Variable_declaration_statement::do_traverse(Traverse*)
-{
- return TRAVERSE_CONTINUE;
-}
-
-// Traverse the assignments in a variable declaration. Note that this
-// traversal is different from the usual traversal.
-
-bool
-Variable_declaration_statement::do_traverse_assignments(
- Traverse_assignments* tassign)
-{
- tassign->initialize_variable(this->var_);
- return true;
-}
-
-// Lower the variable's initialization expression.
-
-Statement*
-Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function,
- Block*, Statement_inserter* inserter)
-{
- this->var_->var_value()->lower_init_expression(gogo, function, inserter);
- return this;
-}
-
-// Convert a variable declaration to the backend representation.
-
-Bstatement*
-Variable_declaration_statement::do_get_backend(Translate_context* context)
-{
- Variable* var = this->var_->var_value();
- Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
- context->function());
- tree init = var->get_init_tree(context->gogo(), context->function());
- Bexpression* binit = init == NULL ? NULL : tree_to_expr(init);
-
- if (!var->is_in_heap())
- {
- go_assert(binit != NULL);
- return context->backend()->init_statement(bvar, binit);
- }
-
- // Something takes the address of this variable, so the value is
- // stored in the heap. Initialize it to newly allocated memory
- // space, and assign the initial value to the new space.
- Location loc = this->location();
- Named_object* newfn = context->gogo()->lookup_global("new");
- go_assert(newfn != NULL && newfn->is_function_declaration());
- Expression* func = Expression::make_func_reference(newfn, NULL, loc);
- Expression_list* params = new Expression_list();
- params->push_back(Expression::make_type(var->type(), loc));
- Expression* call = Expression::make_call(func, params, false, loc);
- context->gogo()->lower_expression(context->function(), NULL, &call);
- Temporary_statement* temp = Statement::make_temporary(NULL, call, loc);
- Bstatement* btemp = temp->get_backend(context);
-
- Bstatement* set = NULL;
- if (binit != NULL)
- {
- Expression* e = Expression::make_temporary_reference(temp, loc);
- e = Expression::make_unary(OPERATOR_MULT, e, loc);
- Bexpression* be = tree_to_expr(e->get_tree(context));
- set = context->backend()->assignment_statement(be, binit, loc);
- }
-
- Expression* ref = Expression::make_temporary_reference(temp, loc);
- Bexpression* bref = tree_to_expr(ref->get_tree(context));
- Bstatement* sinit = context->backend()->init_statement(bvar, bref);
-
- std::vector<Bstatement*> stats;
- stats.reserve(3);
- stats.push_back(btemp);
- if (set != NULL)
- stats.push_back(set);
- stats.push_back(sinit);
- return context->backend()->statement_list(stats);
-}
-
-// Dump the AST representation for a variable declaration.
-
-void
-Variable_declaration_statement::do_dump_statement(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
-
- go_assert(var_->is_variable());
- ast_dump_context->ostream() << "var " << this->var_->name() << " ";
- Variable* var = this->var_->var_value();
- if (var->has_type())
- {
- ast_dump_context->dump_type(var->type());
- ast_dump_context->ostream() << " ";
- }
- if (var->init() != NULL)
- {
- ast_dump_context->ostream() << "= ";
- ast_dump_context->dump_expression(var->init());
- }
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a variable declaration.
-
-Statement*
-Statement::make_variable_declaration(Named_object* var)
-{
- return new Variable_declaration_statement(var);
-}
-
-// Class Temporary_statement.
-
-// Return the type of the temporary variable.
-
-Type*
-Temporary_statement::type() const
-{
- return this->type_ != NULL ? this->type_ : this->init_->type();
-}
-
-// Traversal.
-
-int
-Temporary_statement::do_traverse(Traverse* traverse)
-{
- if (this->type_ != NULL
- && this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (this->init_ == NULL)
- return TRAVERSE_CONTINUE;
- else
- return this->traverse_expression(traverse, &this->init_);
-}
-
-// Traverse assignments.
-
-bool
-Temporary_statement::do_traverse_assignments(Traverse_assignments* tassign)
-{
- if (this->init_ == NULL)
- return false;
- tassign->value(&this->init_, true, true);
- return true;
-}
-
-// Determine types.
-
-void
-Temporary_statement::do_determine_types()
-{
- if (this->type_ != NULL && this->type_->is_abstract())
- this->type_ = this->type_->make_non_abstract_type();
-
- if (this->init_ != NULL)
- {
- if (this->type_ == NULL)
- this->init_->determine_type_no_context();
- else
- {
- Type_context context(this->type_, false);
- this->init_->determine_type(&context);
- }
- }
-
- if (this->type_ == NULL)
- {
- this->type_ = this->init_->type();
- go_assert(!this->type_->is_abstract());
- }
-}
-
-// Check types.
-
-void
-Temporary_statement::do_check_types(Gogo*)
-{
- if (this->type_ != NULL && this->init_ != NULL)
- {
- std::string reason;
- bool ok;
- if (this->are_hidden_fields_ok_)
- ok = Type::are_assignable_hidden_ok(this->type_, this->init_->type(),
- &reason);
- else
- ok = Type::are_assignable(this->type_, this->init_->type(), &reason);
- if (!ok)
- {
- if (reason.empty())
- error_at(this->location(), "incompatible types in assignment");
- else
- error_at(this->location(), "incompatible types in assignment (%s)",
- reason.c_str());
- this->set_is_error();
- }
- }
-}
-
-// Convert to backend representation.
-
-Bstatement*
-Temporary_statement::do_get_backend(Translate_context* context)
-{
- go_assert(this->bvariable_ == NULL);
-
- // FIXME: Permitting FUNCTION to be NULL here is a temporary measure
- // until we have a better representation of the init function.
- Named_object* function = context->function();
- Bfunction* bfunction;
- if (function == NULL)
- bfunction = NULL;
- else
- bfunction = tree_to_function(function->func_value()->get_decl());
-
- Btype* btype = this->type()->get_backend(context->gogo());
-
- Bexpression* binit;
- if (this->init_ == NULL)
- binit = NULL;
- else if (this->type_ == NULL)
- binit = tree_to_expr(this->init_->get_tree(context));
- else
- {
- Expression* init = Expression::make_cast(this->type_, this->init_,
- this->location());
- context->gogo()->lower_expression(context->function(), NULL, &init);
- binit = tree_to_expr(init->get_tree(context));
- }
-
- Bstatement* statement;
- this->bvariable_ =
- context->backend()->temporary_variable(bfunction, context->bblock(),
- btype, binit,
- this->is_address_taken_,
- this->location(), &statement);
- return statement;
-}
-
-// Return the backend variable.
-
-Bvariable*
-Temporary_statement::get_backend_variable(Translate_context* context) const
-{
- if (this->bvariable_ == NULL)
- {
- go_assert(saw_errors());
- return context->backend()->error_variable();
- }
- return this->bvariable_;
-}
-
-// Dump the AST represemtation for a temporary statement
-
-void
-Temporary_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_temp_variable_name(this);
- if (this->type_ != NULL)
- {
- ast_dump_context->ostream() << " ";
- ast_dump_context->dump_type(this->type_);
- }
- if (this->init_ != NULL)
- {
- ast_dump_context->ostream() << " = ";
- ast_dump_context->dump_expression(this->init_);
- }
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make and initialize a temporary variable in BLOCK.
-
-Temporary_statement*
-Statement::make_temporary(Type* type, Expression* init,
- Location location)
-{
- return new Temporary_statement(type, init, location);
-}
-
-// An assignment statement.
-
-class Assignment_statement : public Statement
-{
- public:
- Assignment_statement(Expression* lhs, Expression* rhs,
- Location location)
- : Statement(STATEMENT_ASSIGNMENT, location),
- lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
- { }
-
- // Note that it is OK for this assignment statement to set hidden
- // fields.
- void
- set_hidden_fields_are_ok()
- { this->are_hidden_fields_ok_ = true; }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- bool
- do_traverse_assignments(Traverse_assignments*);
-
- void
- do_determine_types();
-
- void
- do_check_types(Gogo*);
-
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // Left hand side--the lvalue.
- Expression* lhs_;
- // Right hand side--the rvalue.
- Expression* rhs_;
- // True if this statement may set hidden fields in the assignment
- // statement. This is used for generated method stubs.
- bool are_hidden_fields_ok_;
-};
-
-// Traversal.
-
-int
-Assignment_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return this->traverse_expression(traverse, &this->rhs_);
-}
-
-bool
-Assignment_statement::do_traverse_assignments(Traverse_assignments* tassign)
-{
- tassign->assignment(&this->lhs_, &this->rhs_);
- return true;
-}
-
-// Set types for the assignment.
-
-void
-Assignment_statement::do_determine_types()
-{
- this->lhs_->determine_type_no_context();
- Type_context context(this->lhs_->type(), false);
- this->rhs_->determine_type(&context);
-}
-
-// Check types for an assignment.
-
-void
-Assignment_statement::do_check_types(Gogo*)
-{
- // The left hand side must be either addressable, a map index
- // expression, or the blank identifier.
- if (!this->lhs_->is_addressable()
- && this->lhs_->map_index_expression() == NULL
- && !this->lhs_->is_sink_expression())
- {
- if (!this->lhs_->type()->is_error())
- this->report_error(_("invalid left hand side of assignment"));
- return;
- }
-
- Type* lhs_type = this->lhs_->type();
- Type* rhs_type = this->rhs_->type();
- std::string reason;
- bool ok;
- if (this->are_hidden_fields_ok_)
- ok = Type::are_assignable_hidden_ok(lhs_type, rhs_type, &reason);
- else
- ok = Type::are_assignable(lhs_type, rhs_type, &reason);
- if (!ok)
- {
- if (reason.empty())
- error_at(this->location(), "incompatible types in assignment");
- else
- error_at(this->location(), "incompatible types in assignment (%s)",
- reason.c_str());
- this->set_is_error();
- }
-
- if (lhs_type->is_error() || rhs_type->is_error())
- this->set_is_error();
-}
-
-// Convert an assignment statement to the backend representation.
-
-Bstatement*
-Assignment_statement::do_get_backend(Translate_context* context)
-{
- tree rhs_tree = this->rhs_->get_tree(context);
- if (this->lhs_->is_sink_expression())
- return context->backend()->expression_statement(tree_to_expr(rhs_tree));
- tree lhs_tree = this->lhs_->get_tree(context);
- rhs_tree = Expression::convert_for_assignment(context, this->lhs_->type(),
- this->rhs_->type(), rhs_tree,
- this->location());
- return context->backend()->assignment_statement(tree_to_expr(lhs_tree),
- tree_to_expr(rhs_tree),
- this->location());
-}
-
-// Dump the AST representation for an assignment statement.
-
-void
-Assignment_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
- const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_expression(this->lhs_);
- ast_dump_context->ostream() << " = " ;
- ast_dump_context->dump_expression(this->rhs_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make an assignment statement.
-
-Statement*
-Statement::make_assignment(Expression* lhs, Expression* rhs,
- Location location)
-{
- return new Assignment_statement(lhs, rhs, location);
-}
-
-// The Move_subexpressions class is used to move all top-level
-// subexpressions of an expression. This is used for things like
-// index expressions in which we must evaluate the index value before
-// it can be changed by a multiple assignment.
-
-class Move_subexpressions : public Traverse
-{
- public:
- Move_subexpressions(int skip, Block* block)
- : Traverse(traverse_expressions),
- skip_(skip), block_(block)
- { }
-
- protected:
- int
- expression(Expression**);
-
- private:
- // The number of subexpressions to skip moving. This is used to
- // avoid moving the array itself, as we only need to move the index.
- int skip_;
- // The block where new temporary variables should be added.
- Block* block_;
-};
-
-int
-Move_subexpressions::expression(Expression** pexpr)
-{
- if (this->skip_ > 0)
- --this->skip_;
- else if ((*pexpr)->temporary_reference_expression() == NULL)
- {
- Location loc = (*pexpr)->location();
- Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
- this->block_->add_statement(temp);
- *pexpr = Expression::make_temporary_reference(temp, loc);
- }
- // We only need to move top-level subexpressions.
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// The Move_ordered_evals class is used to find any subexpressions of
-// an expression that have an evaluation order dependency. It creates
-// temporary variables to hold them.
-
-class Move_ordered_evals : public Traverse
-{
- public:
- Move_ordered_evals(Block* block)
- : Traverse(traverse_expressions),
- block_(block)
- { }
-
- protected:
- int
- expression(Expression**);
-
- private:
- // The block where new temporary variables should be added.
- Block* block_;
-};
-
-int
-Move_ordered_evals::expression(Expression** pexpr)
-{
- // We have to look at subexpressions first.
- if ((*pexpr)->traverse_subexpressions(this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
-
- int i;
- if ((*pexpr)->must_eval_subexpressions_in_order(&i))
- {
- Move_subexpressions ms(i, this->block_);
- if ((*pexpr)->traverse_subexpressions(&ms) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
-
- if ((*pexpr)->must_eval_in_order())
- {
- Location loc = (*pexpr)->location();
- Temporary_statement* temp = Statement::make_temporary(NULL, *pexpr, loc);
- this->block_->add_statement(temp);
- *pexpr = Expression::make_temporary_reference(temp, loc);
- }
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// An assignment operation statement.
-
-class Assignment_operation_statement : public Statement
-{
- public:
- Assignment_operation_statement(Operator op, Expression* lhs, Expression* rhs,
- Location location)
- : Statement(STATEMENT_ASSIGNMENT_OPERATION, location),
- op_(op), lhs_(lhs), rhs_(rhs)
- { }
-
- protected:
- int
- do_traverse(Traverse*);
-
- bool
- do_traverse_assignments(Traverse_assignments*)
- { go_unreachable(); }
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The operator (OPERATOR_PLUSEQ, etc.).
- Operator op_;
- // Left hand side.
- Expression* lhs_;
- // Right hand side.
- Expression* rhs_;
-};
-
-// Traversal.
-
-int
-Assignment_operation_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression(traverse, &this->lhs_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return this->traverse_expression(traverse, &this->rhs_);
-}
-
-// Lower an assignment operation statement to a regular assignment
-// statement.
-
-Statement*
-Assignment_operation_statement::do_lower(Gogo*, Named_object*,
- Block* enclosing, Statement_inserter*)
-{
- Location loc = this->location();
-
- // We have to evaluate the left hand side expression only once. We
- // do this by moving out any expression with side effects.
- Block* b = new Block(enclosing, loc);
- Move_ordered_evals moe(b);
- this->lhs_->traverse_subexpressions(&moe);
-
- Expression* lval = this->lhs_->copy();
-
- Operator op;
- switch (this->op_)
- {
- case OPERATOR_PLUSEQ:
- op = OPERATOR_PLUS;
- break;
- case OPERATOR_MINUSEQ:
- op = OPERATOR_MINUS;
- break;
- case OPERATOR_OREQ:
- op = OPERATOR_OR;
- break;
- case OPERATOR_XOREQ:
- op = OPERATOR_XOR;
- break;
- case OPERATOR_MULTEQ:
- op = OPERATOR_MULT;
- break;
- case OPERATOR_DIVEQ:
- op = OPERATOR_DIV;
- break;
- case OPERATOR_MODEQ:
- op = OPERATOR_MOD;
- break;
- case OPERATOR_LSHIFTEQ:
- op = OPERATOR_LSHIFT;
- break;
- case OPERATOR_RSHIFTEQ:
- op = OPERATOR_RSHIFT;
- break;
- case OPERATOR_ANDEQ:
- op = OPERATOR_AND;
- break;
- case OPERATOR_BITCLEAREQ:
- op = OPERATOR_BITCLEAR;
- break;
- default:
- go_unreachable();
- }
-
- Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc);
- Statement* s = Statement::make_assignment(this->lhs_, binop, loc);
- if (b->statements()->empty())
- {
- delete b;
- return s;
- }
- else
- {
- b->add_statement(s);
- return Statement::make_block_statement(b, loc);
- }
-}
-
-// Dump the AST representation for an assignment operation statement
-
-void
-Assignment_operation_statement::do_dump_statement(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_expression(this->lhs_);
- ast_dump_context->dump_operator(this->op_);
- ast_dump_context->dump_expression(this->rhs_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make an assignment operation statement.
-
-Statement*
-Statement::make_assignment_operation(Operator op, Expression* lhs,
- Expression* rhs, Location location)
-{
- return new Assignment_operation_statement(op, lhs, rhs, location);
-}
-
-// A tuple assignment statement. This differs from an assignment
-// statement in that the right-hand-side expressions are evaluated in
-// parallel.
-
-class Tuple_assignment_statement : public Statement
-{
- public:
- Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs,
- Location location)
- : Statement(STATEMENT_TUPLE_ASSIGNMENT, location),
- lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
- { }
-
- // Note that it is OK for this assignment statement to set hidden
- // fields.
- void
- set_hidden_fields_are_ok()
- { this->are_hidden_fields_ok_ = true; }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- bool
- do_traverse_assignments(Traverse_assignments*)
- { go_unreachable(); }
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // Left hand side--a list of lvalues.
- Expression_list* lhs_;
- // Right hand side--a list of rvalues.
- Expression_list* rhs_;
- // True if this statement may set hidden fields in the assignment
- // statement. This is used for generated method stubs.
- bool are_hidden_fields_ok_;
-};
-
-// Traversal.
-
-int
-Tuple_assignment_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression_list(traverse, this->lhs_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return this->traverse_expression_list(traverse, this->rhs_);
-}
-
-// Lower a tuple assignment. We use temporary variables to split it
-// up into a set of single assignments.
-
-Statement*
-Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
- Statement_inserter*)
-{
- Location loc = this->location();
-
- Block* b = new Block(enclosing, loc);
-
- // First move out any subexpressions on the left hand side. The
- // right hand side will be evaluated in the required order anyhow.
- Move_ordered_evals moe(b);
- for (Expression_list::iterator plhs = this->lhs_->begin();
- plhs != this->lhs_->end();
- ++plhs)
- Expression::traverse(&*plhs, &moe);
-
- std::vector<Temporary_statement*> temps;
- temps.reserve(this->lhs_->size());
-
- Expression_list::const_iterator prhs = this->rhs_->begin();
- for (Expression_list::const_iterator plhs = this->lhs_->begin();
- plhs != this->lhs_->end();
- ++plhs, ++prhs)
- {
- go_assert(prhs != this->rhs_->end());
-
- if ((*plhs)->is_error_expression()
- || (*plhs)->type()->is_error()
- || (*prhs)->is_error_expression()
- || (*prhs)->type()->is_error())
- continue;
-
- if ((*plhs)->is_sink_expression())
- {
- b->add_statement(Statement::make_statement(*prhs, true));
- continue;
- }
-
- Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
- *prhs, loc);
- if (this->are_hidden_fields_ok_)
- temp->set_hidden_fields_are_ok();
- b->add_statement(temp);
- temps.push_back(temp);
-
- }
- go_assert(prhs == this->rhs_->end());
-
- prhs = this->rhs_->begin();
- std::vector<Temporary_statement*>::const_iterator ptemp = temps.begin();
- for (Expression_list::const_iterator plhs = this->lhs_->begin();
- plhs != this->lhs_->end();
- ++plhs, ++prhs)
- {
- if ((*plhs)->is_error_expression()
- || (*plhs)->type()->is_error()
- || (*prhs)->is_error_expression()
- || (*prhs)->type()->is_error())
- continue;
-
- if ((*plhs)->is_sink_expression())
- continue;
-
- Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
- Statement* s = Statement::make_assignment(*plhs, ref, loc);
- if (this->are_hidden_fields_ok_)
- {
- Assignment_statement* as = static_cast<Assignment_statement*>(s);
- as->set_hidden_fields_are_ok();
- }
- b->add_statement(s);
- ++ptemp;
- }
- go_assert(ptemp == temps.end() || saw_errors());
-
- return Statement::make_block_statement(b, loc);
-}
-
-// Dump the AST representation for a tuple assignment statement.
-
-void
-Tuple_assignment_statement::do_dump_statement(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_expression_list(this->lhs_);
- ast_dump_context->ostream() << " = ";
- ast_dump_context->dump_expression_list(this->rhs_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a tuple assignment statement.
-
-Statement*
-Statement::make_tuple_assignment(Expression_list* lhs, Expression_list* rhs,
- Location location)
-{
- return new Tuple_assignment_statement(lhs, rhs, location);
-}
-
-// A tuple assignment from a map index expression.
-// v, ok = m[k]
-
-class Tuple_map_assignment_statement : public Statement
-{
-public:
- Tuple_map_assignment_statement(Expression* val, Expression* present,
- Expression* map_index,
- Location location)
- : Statement(STATEMENT_TUPLE_MAP_ASSIGNMENT, location),
- val_(val), present_(present), map_index_(map_index)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- bool
- do_traverse_assignments(Traverse_assignments*)
- { go_unreachable(); }
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // Lvalue which receives the value from the map.
- Expression* val_;
- // Lvalue which receives whether the key value was present.
- Expression* present_;
- // The map index expression.
- Expression* map_index_;
-};
-
-// Traversal.
-
-int
-Tuple_map_assignment_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
- || this->traverse_expression(traverse, &this->present_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return this->traverse_expression(traverse, &this->map_index_);
-}
-
-// Lower a tuple map assignment.
-
-Statement*
-Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
- Block* enclosing, Statement_inserter*)
-{
- Location loc = this->location();
-
- Map_index_expression* map_index = this->map_index_->map_index_expression();
- if (map_index == NULL)
- {
- this->report_error(_("expected map index on right hand side"));
- return Statement::make_error_statement(loc);
- }
- Map_type* map_type = map_index->get_map_type();
- if (map_type == NULL)
- return Statement::make_error_statement(loc);
-
- Block* b = new Block(enclosing, loc);
-
- // Move out any subexpressions to make sure that functions are
- // called in the required order.
- Move_ordered_evals moe(b);
- this->val_->traverse_subexpressions(&moe);
- this->present_->traverse_subexpressions(&moe);
-
- // Copy the key value into a temporary so that we can take its
- // address without pushing the value onto the heap.
-
- // var key_temp KEY_TYPE = MAP_INDEX
- Temporary_statement* key_temp =
- Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
- b->add_statement(key_temp);
-
- // var val_temp VAL_TYPE
- Temporary_statement* val_temp =
- Statement::make_temporary(map_type->val_type(), NULL, loc);
- b->add_statement(val_temp);
-
- // var present_temp bool
- Temporary_statement* present_temp =
- Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
- b->add_statement(present_temp);
-
- // present_temp = mapaccess2(DESCRIPTOR, MAP, &key_temp, &val_temp)
- Expression* a1 = Expression::make_type_descriptor(map_type, loc);
- Expression* a2 = map_index->map();
- Temporary_reference_expression* ref =
- Expression::make_temporary_reference(key_temp, loc);
- Expression* a3 = Expression::make_unary(OPERATOR_AND, ref, loc);
- ref = Expression::make_temporary_reference(val_temp, loc);
- Expression* a4 = Expression::make_unary(OPERATOR_AND, ref, loc);
- Expression* call = Runtime::make_call(Runtime::MAPACCESS2, loc, 4,
- a1, a2, a3, a4);
-
- ref = Expression::make_temporary_reference(present_temp, loc);
- ref->set_is_lvalue();
- Statement* s = Statement::make_assignment(ref, call, loc);
- b->add_statement(s);
-
- // val = val_temp
- ref = Expression::make_temporary_reference(val_temp, loc);
- s = Statement::make_assignment(this->val_, ref, loc);
- b->add_statement(s);
-
- // present = present_temp
- ref = Expression::make_temporary_reference(present_temp, loc);
- s = Statement::make_assignment(this->present_, ref, loc);
- b->add_statement(s);
-
- return Statement::make_block_statement(b, loc);
-}
-
-// Dump the AST representation for a tuple map assignment statement.
-
-void
-Tuple_map_assignment_statement::do_dump_statement(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_expression(this->val_);
- ast_dump_context->ostream() << ", ";
- ast_dump_context->dump_expression(this->present_);
- ast_dump_context->ostream() << " = ";
- ast_dump_context->dump_expression(this->map_index_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a map assignment statement which returns a pair of values.
-
-Statement*
-Statement::make_tuple_map_assignment(Expression* val, Expression* present,
- Expression* map_index,
- Location location)
-{
- return new Tuple_map_assignment_statement(val, present, map_index, location);
-}
-
-// Assign a pair of entries to a map.
-// m[k] = v, p
-
-class Map_assignment_statement : public Statement
-{
- public:
- Map_assignment_statement(Expression* map_index,
- Expression* val, Expression* should_set,
- Location location)
- : Statement(STATEMENT_MAP_ASSIGNMENT, location),
- map_index_(map_index), val_(val), should_set_(should_set)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- bool
- do_traverse_assignments(Traverse_assignments*)
- { go_unreachable(); }
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // A reference to the map index which should be set or deleted.
- Expression* map_index_;
- // The value to add to the map.
- Expression* val_;
- // Whether or not to add the value.
- Expression* should_set_;
-};
-
-// Traverse a map assignment.
-
-int
-Map_assignment_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression(traverse, &this->map_index_) == TRAVERSE_EXIT
- || this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return this->traverse_expression(traverse, &this->should_set_);
-}
-
-// Lower a map assignment to a function call.
-
-Statement*
-Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
- Statement_inserter*)
-{
- Location loc = this->location();
-
- Map_index_expression* map_index = this->map_index_->map_index_expression();
- if (map_index == NULL)
- {
- this->report_error(_("expected map index on left hand side"));
- return Statement::make_error_statement(loc);
- }
- Map_type* map_type = map_index->get_map_type();
- if (map_type == NULL)
- return Statement::make_error_statement(loc);
-
- Block* b = new Block(enclosing, loc);
-
- // Evaluate the map first to get order of evaluation right.
- // map_temp := m // we are evaluating m[k] = v, p
- Temporary_statement* map_temp = Statement::make_temporary(map_type,
- map_index->map(),
- loc);
- b->add_statement(map_temp);
-
- // var key_temp MAP_KEY_TYPE = k
- Temporary_statement* key_temp =
- Statement::make_temporary(map_type->key_type(), map_index->index(), loc);
- b->add_statement(key_temp);
-
- // var val_temp MAP_VAL_TYPE = v
- Temporary_statement* val_temp =
- Statement::make_temporary(map_type->val_type(), this->val_, loc);
- b->add_statement(val_temp);
-
- // var insert_temp bool = p
- Temporary_statement* insert_temp =
- Statement::make_temporary(Type::lookup_bool_type(), this->should_set_,
- loc);
- b->add_statement(insert_temp);
-
- // mapassign2(map_temp, &key_temp, &val_temp, p)
- Expression* p1 = Expression::make_temporary_reference(map_temp, loc);
- Expression* ref = Expression::make_temporary_reference(key_temp, loc);
- Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
- ref = Expression::make_temporary_reference(val_temp, loc);
- Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
- Expression* p4 = Expression::make_temporary_reference(insert_temp, loc);
- Expression* call = Runtime::make_call(Runtime::MAPASSIGN2, loc, 4,
- p1, p2, p3, p4);
- Statement* s = Statement::make_statement(call, true);
- b->add_statement(s);
-
- return Statement::make_block_statement(b, loc);
-}
-
-// Dump the AST representation for a map assignment statement.
-
-void
-Map_assignment_statement::do_dump_statement(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_expression(this->map_index_);
- ast_dump_context->ostream() << " = ";
- ast_dump_context->dump_expression(this->val_);
- ast_dump_context->ostream() << ", ";
- ast_dump_context->dump_expression(this->should_set_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a statement which assigns a pair of entries to a map.
-
-Statement*
-Statement::make_map_assignment(Expression* map_index,
- Expression* val, Expression* should_set,
- Location location)
-{
- return new Map_assignment_statement(map_index, val, should_set, location);
-}
-
-// A tuple assignment from a receive statement.
-
-class Tuple_receive_assignment_statement : public Statement
-{
- public:
- Tuple_receive_assignment_statement(Expression* val, Expression* closed,
- Expression* channel, Location location)
- : Statement(STATEMENT_TUPLE_RECEIVE_ASSIGNMENT, location),
- val_(val), closed_(closed), channel_(channel)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- bool
- do_traverse_assignments(Traverse_assignments*)
- { go_unreachable(); }
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // Lvalue which receives the value from the channel.
- Expression* val_;
- // Lvalue which receives whether the channel is closed.
- Expression* closed_;
- // The channel on which we receive the value.
- Expression* channel_;
-};
-
-// Traversal.
-
-int
-Tuple_receive_assignment_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
- || this->traverse_expression(traverse, &this->closed_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return this->traverse_expression(traverse, &this->channel_);
-}
-
-// Lower to a function call.
-
-Statement*
-Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
- Block* enclosing,
- Statement_inserter*)
-{
- Location loc = this->location();
-
- Channel_type* channel_type = this->channel_->type()->channel_type();
- if (channel_type == NULL)
- {
- this->report_error(_("expected channel"));
- return Statement::make_error_statement(loc);
- }
- if (!channel_type->may_receive())
- {
- this->report_error(_("invalid receive on send-only channel"));
- return Statement::make_error_statement(loc);
- }
-
- Block* b = new Block(enclosing, loc);
-
- // Make sure that any subexpressions on the left hand side are
- // evaluated in the right order.
- Move_ordered_evals moe(b);
- this->val_->traverse_subexpressions(&moe);
- this->closed_->traverse_subexpressions(&moe);
-
- // var val_temp ELEMENT_TYPE
- Temporary_statement* val_temp =
- Statement::make_temporary(channel_type->element_type(), NULL, loc);
- b->add_statement(val_temp);
-
- // var closed_temp bool
- Temporary_statement* closed_temp =
- Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
- b->add_statement(closed_temp);
-
- // closed_temp = chanrecv2(type, channel, &val_temp)
- Expression* td = Expression::make_type_descriptor(this->channel_->type(),
- loc);
- Temporary_reference_expression* ref =
- Expression::make_temporary_reference(val_temp, loc);
- Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
- Expression* call = Runtime::make_call(Runtime::CHANRECV2,
- loc, 3, td, this->channel_, p2);
- ref = Expression::make_temporary_reference(closed_temp, loc);
- ref->set_is_lvalue();
- Statement* s = Statement::make_assignment(ref, call, loc);
- b->add_statement(s);
-
- // val = val_temp
- ref = Expression::make_temporary_reference(val_temp, loc);
- s = Statement::make_assignment(this->val_, ref, loc);
- b->add_statement(s);
-
- // closed = closed_temp
- ref = Expression::make_temporary_reference(closed_temp, loc);
- s = Statement::make_assignment(this->closed_, ref, loc);
- b->add_statement(s);
-
- return Statement::make_block_statement(b, loc);
-}
-
-// Dump the AST representation for a tuple receive statement.
-
-void
-Tuple_receive_assignment_statement::do_dump_statement(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_expression(this->val_);
- ast_dump_context->ostream() << ", ";
- ast_dump_context->dump_expression(this->closed_);
- ast_dump_context->ostream() << " <- ";
- ast_dump_context->dump_expression(this->channel_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a nonblocking receive statement.
-
-Statement*
-Statement::make_tuple_receive_assignment(Expression* val, Expression* closed,
- Expression* channel,
- Location location)
-{
- return new Tuple_receive_assignment_statement(val, closed, channel,
- location);
-}
-
-// An assignment to a pair of values from a type guard. This is a
-// conditional type guard. v, ok = i.(type).
-
-class Tuple_type_guard_assignment_statement : public Statement
-{
- public:
- Tuple_type_guard_assignment_statement(Expression* val, Expression* ok,
- Expression* expr, Type* type,
- Location location)
- : Statement(STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT, location),
- val_(val), ok_(ok), expr_(expr), type_(type)
- { }
-
- protected:
- int
- do_traverse(Traverse*);
-
- bool
- do_traverse_assignments(Traverse_assignments*)
- { go_unreachable(); }
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- Call_expression*
- lower_to_type(Runtime::Function);
-
- void
- lower_to_object_type(Block*, Runtime::Function);
-
- // The variable which recieves the converted value.
- Expression* val_;
- // The variable which receives the indication of success.
- Expression* ok_;
- // The expression being converted.
- Expression* expr_;
- // The type to which the expression is being converted.
- Type* type_;
-};
-
-// Traverse a type guard tuple assignment.
-
-int
-Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT
- || this->traverse_expression(traverse, &this->ok_) == TRAVERSE_EXIT
- || this->traverse_type(traverse, this->type_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return this->traverse_expression(traverse, &this->expr_);
-}
-
-// Lower to a function call.
-
-Statement*
-Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
- Block* enclosing,
- Statement_inserter*)
-{
- Location loc = this->location();
-
- Type* expr_type = this->expr_->type();
- if (expr_type->interface_type() == NULL)
- {
- if (!expr_type->is_error() && !this->type_->is_error())
- this->report_error(_("type assertion only valid for interface types"));
- return Statement::make_error_statement(loc);
- }
-
- Block* b = new Block(enclosing, loc);
-
- // Make sure that any subexpressions on the left hand side are
- // evaluated in the right order.
- Move_ordered_evals moe(b);
- this->val_->traverse_subexpressions(&moe);
- this->ok_->traverse_subexpressions(&moe);
-
- bool expr_is_empty = expr_type->interface_type()->is_empty();
- Call_expression* call;
- if (this->type_->interface_type() != NULL)
- {
- if (this->type_->interface_type()->is_empty())
- call = Runtime::make_call((expr_is_empty
- ? Runtime::IFACEE2E2
- : Runtime::IFACEI2E2),
- loc, 1, this->expr_);
- else
- call = this->lower_to_type(expr_is_empty
- ? Runtime::IFACEE2I2
- : Runtime::IFACEI2I2);
- }
- else if (this->type_->points_to() != NULL)
- call = this->lower_to_type(expr_is_empty
- ? Runtime::IFACEE2T2P
- : Runtime::IFACEI2T2P);
- else
- {
- this->lower_to_object_type(b,
- (expr_is_empty
- ? Runtime::IFACEE2T2
- : Runtime::IFACEI2T2));
- call = NULL;
- }
-
- if (call != NULL)
- {
- Expression* res = Expression::make_call_result(call, 0);
- res = Expression::make_unsafe_cast(this->type_, res, loc);
- Statement* s = Statement::make_assignment(this->val_, res, loc);
- b->add_statement(s);
-
- res = Expression::make_call_result(call, 1);
- s = Statement::make_assignment(this->ok_, res, loc);
- b->add_statement(s);
- }
-
- return Statement::make_block_statement(b, loc);
-}
-
-// Lower a conversion to a non-empty interface type or a pointer type.
-
-Call_expression*
-Tuple_type_guard_assignment_statement::lower_to_type(Runtime::Function code)
-{
- Location loc = this->location();
- return Runtime::make_call(code, loc, 2,
- Expression::make_type_descriptor(this->type_, loc),
- this->expr_);
-}
-
-// Lower a conversion to a non-interface non-pointer type.
-
-void
-Tuple_type_guard_assignment_statement::lower_to_object_type(
- Block* b,
- Runtime::Function code)
-{
- Location loc = this->location();
-
- // var val_temp TYPE
- Temporary_statement* val_temp = Statement::make_temporary(this->type_,
- NULL, loc);
- b->add_statement(val_temp);
-
- // ok = CODE(type_descriptor, expr, &val_temp)
- Expression* p1 = Expression::make_type_descriptor(this->type_, loc);
- Expression* ref = Expression::make_temporary_reference(val_temp, loc);
- Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
- Expression* call = Runtime::make_call(code, loc, 3, p1, this->expr_, p3);
- Statement* s = Statement::make_assignment(this->ok_, call, loc);
- b->add_statement(s);
-
- // val = val_temp
- ref = Expression::make_temporary_reference(val_temp, loc);
- s = Statement::make_assignment(this->val_, ref, loc);
- b->add_statement(s);
-}
-
-// Dump the AST representation for a tuple type guard statement.
-
-void
-Tuple_type_guard_assignment_statement::do_dump_statement(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_expression(this->val_);
- ast_dump_context->ostream() << ", ";
- ast_dump_context->dump_expression(this->ok_);
- ast_dump_context->ostream() << " = ";
- ast_dump_context->dump_expression(this->expr_);
- ast_dump_context->ostream() << " . ";
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make an assignment from a type guard to a pair of variables.
-
-Statement*
-Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok,
- Expression* expr, Type* type,
- Location location)
-{
- return new Tuple_type_guard_assignment_statement(val, ok, expr, type,
- location);
-}
-
-// An expression statement.
-
-class Expression_statement : public Statement
-{
- public:
- Expression_statement(Expression* expr, bool is_ignored)
- : Statement(STATEMENT_EXPRESSION, expr->location()),
- expr_(expr), is_ignored_(is_ignored)
- { }
-
- Expression*
- expr()
- { return this->expr_; }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return this->traverse_expression(traverse, &this->expr_); }
-
- void
- do_determine_types()
- { this->expr_->determine_type_no_context(); }
-
- void
- do_check_types(Gogo*);
-
- bool
- do_may_fall_through() const;
-
- Bstatement*
- do_get_backend(Translate_context* context);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- Expression* expr_;
- // Whether the value of this expression is being explicitly ignored.
- bool is_ignored_;
-};
-
-// Check the types of an expression statement. The only check we do
-// is to possibly give an error about discarding the value of the
-// expression.
-
-void
-Expression_statement::do_check_types(Gogo*)
-{
- if (!this->is_ignored_)
- this->expr_->discarding_value();
-}
-
-// An expression statement may fall through unless it is a call to a
-// function which does not return.
-
-bool
-Expression_statement::do_may_fall_through() const
-{
- const Call_expression* call = this->expr_->call_expression();
- if (call != NULL)
- {
- const Expression* fn = call->fn();
- const Func_expression* fe = fn->func_expression();
- if (fe != NULL)
- {
- const Named_object* no = fe->named_object();
-
- Function_type* fntype;
- if (no->is_function())
- fntype = no->func_value()->type();
- else if (no->is_function_declaration())
- fntype = no->func_declaration_value()->type();
- else
- fntype = NULL;
-
- // The builtin function panic does not return.
- if (fntype != NULL && fntype->is_builtin() && no->name() == "panic")
- return false;
- }
- }
- return true;
-}
-
-// Convert to backend representation.
-
-Bstatement*
-Expression_statement::do_get_backend(Translate_context* context)
-{
- tree expr_tree = this->expr_->get_tree(context);
- return context->backend()->expression_statement(tree_to_expr(expr_tree));
-}
-
-// Dump the AST representation for an expression statement
-
-void
-Expression_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
- const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_expression(expr_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make an expression statement from an Expression.
-
-Statement*
-Statement::make_statement(Expression* expr, bool is_ignored)
-{
- return new Expression_statement(expr, is_ignored);
-}
-
-// A block statement--a list of statements which may include variable
-// definitions.
-
-class Block_statement : public Statement
-{
- public:
- Block_statement(Block* block, Location location)
- : Statement(STATEMENT_BLOCK, location),
- block_(block)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return this->block_->traverse(traverse); }
-
- void
- do_determine_types()
- { this->block_->determine_types(); }
-
- bool
- do_may_fall_through() const
- { return this->block_->may_fall_through(); }
-
- Bstatement*
- do_get_backend(Translate_context* context);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- Block* block_;
-};
-
-// Convert a block to the backend representation of a statement.
-
-Bstatement*
-Block_statement::do_get_backend(Translate_context* context)
-{
- Bblock* bblock = this->block_->get_backend(context);
- return context->backend()->block_statement(bblock);
-}
-
-// Dump the AST for a block statement
-
-void
-Block_statement::do_dump_statement(Ast_dump_context*) const
-{
- // block statement braces are dumped when traversing.
-}
-
-// Make a block statement.
-
-Statement*
-Statement::make_block_statement(Block* block, Location location)
-{
- return new Block_statement(block, location);
-}
-
-// An increment or decrement statement.
-
-class Inc_dec_statement : public Statement
-{
- public:
- Inc_dec_statement(bool is_inc, Expression* expr)
- : Statement(STATEMENT_INCDEC, expr->location()),
- expr_(expr), is_inc_(is_inc)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return this->traverse_expression(traverse, &this->expr_); }
-
- bool
- do_traverse_assignments(Traverse_assignments*)
- { go_unreachable(); }
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The l-value to increment or decrement.
- Expression* expr_;
- // Whether to increment or decrement.
- bool is_inc_;
-};
-
-// Lower to += or -=.
-
-Statement*
-Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
-{
- Location loc = this->location();
-
- mpz_t oval;
- mpz_init_set_ui(oval, 1UL);
- Expression* oexpr = Expression::make_integer(&oval, NULL, loc);
- mpz_clear(oval);
-
- Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ;
- return Statement::make_assignment_operation(op, this->expr_, oexpr, loc);
-}
-
-// Dump the AST representation for a inc/dec statement.
-
-void
-Inc_dec_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_expression(expr_);
- ast_dump_context->ostream() << (is_inc_? "++": "--") << std::endl;
-}
-
-// Make an increment statement.
-
-Statement*
-Statement::make_inc_statement(Expression* expr)
-{
- return new Inc_dec_statement(true, expr);
-}
-
-// Make a decrement statement.
-
-Statement*
-Statement::make_dec_statement(Expression* expr)
-{
- return new Inc_dec_statement(false, expr);
-}
-
-// Class Thunk_statement. This is the base class for go and defer
-// statements.
-
-// Constructor.
-
-Thunk_statement::Thunk_statement(Statement_classification classification,
- Call_expression* call,
- Location location)
- : Statement(classification, location),
- call_(call), struct_type_(NULL)
-{
-}
-
-// Return whether this is a simple statement which does not require a
-// thunk.
-
-bool
-Thunk_statement::is_simple(Function_type* fntype) const
-{
- // We need a thunk to call a method, or to pass a variable number of
- // arguments.
- if (fntype->is_method() || fntype->is_varargs())
- return false;
-
- // A defer statement requires a thunk to set up for whether the
- // function can call recover.
- if (this->classification() == STATEMENT_DEFER)
- return false;
-
- // We can only permit a single parameter of pointer type.
- const Typed_identifier_list* parameters = fntype->parameters();
- if (parameters != NULL
- && (parameters->size() > 1
- || (parameters->size() == 1
- && parameters->begin()->type()->points_to() == NULL)))
- return false;
-
- // If the function returns multiple values, or returns a type other
- // than integer, floating point, or pointer, then it may get a
- // hidden first parameter, in which case we need the more
- // complicated approach. This is true even though we are going to
- // ignore the return value.
- const Typed_identifier_list* results = fntype->results();
- if (results != NULL
- && (results->size() > 1
- || (results->size() == 1
- && !results->begin()->type()->is_basic_type()
- && results->begin()->type()->points_to() == NULL)))
- return false;
-
- // If this calls something which is not a simple function, then we
- // need a thunk.
- Expression* fn = this->call_->call_expression()->fn();
- if (fn->interface_field_reference_expression() != NULL)
- return false;
-
- return true;
-}
-
-// Traverse a thunk statement.
-
-int
-Thunk_statement::do_traverse(Traverse* traverse)
-{
- return this->traverse_expression(traverse, &this->call_);
-}
-
-// We implement traverse_assignment for a thunk statement because it
-// effectively copies the function call.
-
-bool
-Thunk_statement::do_traverse_assignments(Traverse_assignments* tassign)
-{
- Expression* fn = this->call_->call_expression()->fn();
- Expression* fn2 = fn;
- tassign->value(&fn2, true, false);
- return true;
-}
-
-// Determine types in a thunk statement.
-
-void
-Thunk_statement::do_determine_types()
-{
- this->call_->determine_type_no_context();
-
- // Now that we know the types of the call, build the struct used to
- // pass parameters.
- Call_expression* ce = this->call_->call_expression();
- if (ce == NULL)
- return;
- Function_type* fntype = ce->get_function_type();
- if (fntype != NULL && !this->is_simple(fntype))
- this->struct_type_ = this->build_struct(fntype);
-}
-
-// Check types in a thunk statement.
-
-void
-Thunk_statement::do_check_types(Gogo*)
-{
- if (!this->call_->discarding_value())
- return;
- Call_expression* ce = this->call_->call_expression();
- if (ce == NULL)
- {
- if (!this->call_->is_error_expression())
- this->report_error("expected call expression");
- return;
- }
-}
-
-// The Traverse class used to find and simplify thunk statements.
-
-class Simplify_thunk_traverse : public Traverse
-{
- public:
- Simplify_thunk_traverse(Gogo* gogo)
- : Traverse(traverse_functions | traverse_blocks),
- gogo_(gogo), function_(NULL)
- { }
-
- int
- function(Named_object*);
-
- int
- block(Block*);
-
- private:
- // General IR.
- Gogo* gogo_;
- // The function we are traversing.
- Named_object* function_;
-};
-
-// Keep track of the current function while looking for thunks.
-
-int
-Simplify_thunk_traverse::function(Named_object* no)
-{
- go_assert(this->function_ == NULL);
- this->function_ = no;
- int t = no->func_value()->traverse(this);
- this->function_ = NULL;
- if (t == TRAVERSE_EXIT)
- return t;
- return TRAVERSE_SKIP_COMPONENTS;
-}
-
-// Look for thunks in a block.
-
-int
-Simplify_thunk_traverse::block(Block* b)
-{
- // The parser ensures that thunk statements always appear at the end
- // of a block.
- if (b->statements()->size() < 1)
- return TRAVERSE_CONTINUE;
- Thunk_statement* stat = b->statements()->back()->thunk_statement();
- if (stat == NULL)
- return TRAVERSE_CONTINUE;
- if (stat->simplify_statement(this->gogo_, this->function_, b))
- return TRAVERSE_SKIP_COMPONENTS;
- return TRAVERSE_CONTINUE;
-}
-
-// Simplify all thunk statements.
-
-void
-Gogo::simplify_thunk_statements()
-{
- Simplify_thunk_traverse thunk_traverse(this);
- this->traverse(&thunk_traverse);
-}
-
-// Return true if the thunk function is a constant, which means that
-// it does not need to be passed to the thunk routine.
-
-bool
-Thunk_statement::is_constant_function() const
-{
- Call_expression* ce = this->call_->call_expression();
- Function_type* fntype = ce->get_function_type();
- if (fntype == NULL)
- {
- go_assert(saw_errors());
- return false;
- }
- if (fntype->is_builtin())
- return true;
- Expression* fn = ce->fn();
- if (fn->func_expression() != NULL)
- return fn->func_expression()->closure() == NULL;
- if (fn->interface_field_reference_expression() != NULL)
- return true;
- return false;
-}
-
-// Simplify complex thunk statements into simple ones. A complicated
-// thunk statement is one which takes anything other than zero
-// parameters or a single pointer parameter. We rewrite it into code
-// which allocates a struct, stores the parameter values into the
-// struct, and does a simple go or defer statement which passes the
-// struct to a thunk. The thunk does the real call.
-
-bool
-Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
- Block* block)
-{
- if (this->classification() == STATEMENT_ERROR)
- return false;
- if (this->call_->is_error_expression())
- return false;
-
- if (this->classification() == STATEMENT_DEFER)
- {
- // Make sure that the defer stack exists for the function. We
- // will use when converting this statement to the backend
- // representation, but we want it to exist when we start
- // converting the function.
- function->func_value()->defer_stack(this->location());
- }
-
- Call_expression* ce = this->call_->call_expression();
- Function_type* fntype = ce->get_function_type();
- if (fntype == NULL)
- {
- go_assert(saw_errors());
- this->set_is_error();
- return false;
- }
- if (this->is_simple(fntype))
- return false;
-
- Expression* fn = ce->fn();
- Interface_field_reference_expression* interface_method =
- fn->interface_field_reference_expression();
-
- Location location = this->location();
-
- std::string thunk_name = Gogo::thunk_name();
-
- // Build the thunk.
- this->build_thunk(gogo, thunk_name);
-
- // Generate code to call the thunk.
-
- // Get the values to store into the struct which is the single
- // argument to the thunk.
-
- Expression_list* vals = new Expression_list();
- if (!this->is_constant_function())
- vals->push_back(fn);
-
- if (interface_method != NULL)
- vals->push_back(interface_method->expr());
-
- if (ce->args() != NULL)
- {
- for (Expression_list::const_iterator p = ce->args()->begin();
- p != ce->args()->end();
- ++p)
- vals->push_back(*p);
- }
-
- // Build the struct.
- Expression* constructor =
- Expression::make_struct_composite_literal(this->struct_type_, vals,
- location);
-
- // Allocate the initialized struct on the heap.
- constructor = Expression::make_heap_composite(constructor, location);
-
- // Look up the thunk.
- Named_object* named_thunk = gogo->lookup(thunk_name, NULL);
- go_assert(named_thunk != NULL && named_thunk->is_function());
-
- // Build the call.
- Expression* func = Expression::make_func_reference(named_thunk, NULL,
- location);
- Expression_list* params = new Expression_list();
- params->push_back(constructor);
- Call_expression* call = Expression::make_call(func, params, false, location);
-
- // Build the simple go or defer statement.
- Statement* s;
- if (this->classification() == STATEMENT_GO)
- s = Statement::make_go_statement(call, location);
- else if (this->classification() == STATEMENT_DEFER)
- s = Statement::make_defer_statement(call, location);
- else
- go_unreachable();
-
- // The current block should end with the go statement.
- go_assert(block->statements()->size() >= 1);
- go_assert(block->statements()->back() == this);
- block->replace_statement(block->statements()->size() - 1, s);
-
- // We already ran the determine_types pass, so we need to run it now
- // for the new statement.
- s->determine_types();
-
- // Sanity check.
- gogo->check_types_in_block(block);
-
- // Return true to tell the block not to keep looking at statements.
- return true;
-}
-
-// Set the name to use for thunk parameter N.
-
-void
-Thunk_statement::thunk_field_param(int n, char* buf, size_t buflen)
-{
- snprintf(buf, buflen, "a%d", n);
-}
-
-// Build a new struct type to hold the parameters for a complicated
-// thunk statement. FNTYPE is the type of the function call.
-
-Struct_type*
-Thunk_statement::build_struct(Function_type* fntype)
-{
- Location location = this->location();
-
- Struct_field_list* fields = new Struct_field_list();
-
- Call_expression* ce = this->call_->call_expression();
- Expression* fn = ce->fn();
-
- if (!this->is_constant_function())
- {
- // The function to call.
- fields->push_back(Struct_field(Typed_identifier("fn", fntype,
- location)));
- }
-
- // If this thunk statement calls a method on an interface, we pass
- // the interface object to the thunk.
- Interface_field_reference_expression* interface_method =
- fn->interface_field_reference_expression();
- if (interface_method != NULL)
- {
- Typed_identifier tid("object", interface_method->expr()->type(),
- location);
- fields->push_back(Struct_field(tid));
- }
-
- // The predeclared recover function has no argument. However, we
- // add an argument when building recover thunks. Handle that here.
- if (ce->is_recover_call())
- {
- fields->push_back(Struct_field(Typed_identifier("can_recover",
- Type::lookup_bool_type(),
- location)));
- }
-
- const Expression_list* args = ce->args();
- if (args != NULL)
- {
- int i = 0;
- for (Expression_list::const_iterator p = args->begin();
- p != args->end();
- ++p, ++i)
- {
- char buf[50];
- this->thunk_field_param(i, buf, sizeof buf);
- fields->push_back(Struct_field(Typed_identifier(buf, (*p)->type(),
- location)));
- }
- }
-
- return Type::make_struct_type(fields, location);
-}
-
-// Build the thunk we are going to call. This is a brand new, albeit
-// artificial, function.
-
-void
-Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
-{
- Location location = this->location();
-
- Call_expression* ce = this->call_->call_expression();
-
- bool may_call_recover = false;
- if (this->classification() == STATEMENT_DEFER)
- {
- Func_expression* fn = ce->fn()->func_expression();
- if (fn == NULL)
- may_call_recover = true;
- else
- {
- const Named_object* no = fn->named_object();
- if (!no->is_function())
- may_call_recover = true;
- else
- may_call_recover = no->func_value()->calls_recover();
- }
- }
-
- // Build the type of the thunk. The thunk takes a single parameter,
- // which is a pointer to the special structure we build.
- const char* const parameter_name = "__go_thunk_parameter";
- Typed_identifier_list* thunk_parameters = new Typed_identifier_list();
- Type* pointer_to_struct_type = Type::make_pointer_type(this->struct_type_);
- thunk_parameters->push_back(Typed_identifier(parameter_name,
- pointer_to_struct_type,
- location));
-
- Typed_identifier_list* thunk_results = NULL;
- if (may_call_recover)
- {
- // When deferring a function which may call recover, add a
- // return value, to disable tail call optimizations which will
- // break the way we check whether recover is permitted.
- thunk_results = new Typed_identifier_list();
- thunk_results->push_back(Typed_identifier("", Type::lookup_bool_type(),
- location));
- }
-
- Function_type* thunk_type = Type::make_function_type(NULL, thunk_parameters,
- thunk_results,
- location);
-
- // Start building the thunk.
- Named_object* function = gogo->start_function(thunk_name, thunk_type, true,
- location);
-
- gogo->start_block(location);
-
- // For a defer statement, start with a call to
- // __go_set_defer_retaddr. */
- Label* retaddr_label = NULL;
- if (may_call_recover)
- {
- retaddr_label = gogo->add_label_reference("retaddr", location, false);
- Expression* arg = Expression::make_label_addr(retaddr_label, location);
- Expression* call = Runtime::make_call(Runtime::SET_DEFER_RETADDR,
- location, 1, arg);
-
- // This is a hack to prevent the middle-end from deleting the
- // label.
- gogo->start_block(location);
- gogo->add_statement(Statement::make_goto_statement(retaddr_label,
- location));
- Block* then_block = gogo->finish_block(location);
- then_block->determine_types();
-
- Statement* s = Statement::make_if_statement(call, then_block, NULL,
- location);
- s->determine_types();
- gogo->add_statement(s);
- }
-
- // Get a reference to the parameter.
- Named_object* named_parameter = gogo->lookup(parameter_name, NULL);
- go_assert(named_parameter != NULL && named_parameter->is_variable());
-
- // Build the call. Note that the field names are the same as the
- // ones used in build_struct.
- Expression* thunk_parameter = Expression::make_var_reference(named_parameter,
- location);
- thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
- location);
-
- Interface_field_reference_expression* interface_method =
- ce->fn()->interface_field_reference_expression();
-
- Expression* func_to_call;
- unsigned int next_index;
- if (this->is_constant_function())
- {
- func_to_call = ce->fn();
- next_index = 0;
- }
- else
- {
- func_to_call = Expression::make_field_reference(thunk_parameter,
- 0, location);
- next_index = 1;
- }
-
- if (interface_method != NULL)
- {
- // The main program passes the interface object.
- go_assert(next_index == 0);
- Expression* r = Expression::make_field_reference(thunk_parameter, 0,
- location);
- const std::string& name(interface_method->name());
- func_to_call = Expression::make_interface_field_reference(r, name,
- location);
- next_index = 1;
- }
-
- Expression_list* call_params = new Expression_list();
- const Struct_field_list* fields = this->struct_type_->fields();
- Struct_field_list::const_iterator p = fields->begin();
- for (unsigned int i = 0; i < next_index; ++i)
- ++p;
- bool is_recover_call = ce->is_recover_call();
- Expression* recover_arg = NULL;
- for (; p != fields->end(); ++p, ++next_index)
- {
- Expression* thunk_param = Expression::make_var_reference(named_parameter,
- location);
- thunk_param = Expression::make_unary(OPERATOR_MULT, thunk_param,
- location);
- Expression* param = Expression::make_field_reference(thunk_param,
- next_index,
- location);
- if (!is_recover_call)
- call_params->push_back(param);
- else
- {
- go_assert(call_params->empty());
- recover_arg = param;
- }
- }
-
- if (call_params->empty())
- {
- delete call_params;
- call_params = NULL;
- }
-
- Call_expression* call = Expression::make_call(func_to_call, call_params,
- false, location);
-
- // This call expression was already lowered before entering the
- // thunk statement. Don't try to lower varargs again, as that will
- // cause confusion for, e.g., method calls which already have a
- // receiver parameter.
- call->set_varargs_are_lowered();
-
- Statement* call_statement = Statement::make_statement(call, true);
-
- gogo->add_statement(call_statement);
-
- // If this is a defer statement, the label comes immediately after
- // the call.
- if (may_call_recover)
- {
- gogo->add_label_definition("retaddr", location);
-
- Expression_list* vals = new Expression_list();
- vals->push_back(Expression::make_boolean(false, location));
- gogo->add_statement(Statement::make_return_statement(vals, location));
- }
-
- Block* b = gogo->finish_block(location);
-
- gogo->add_block(b, location);
-
- gogo->lower_block(function, b);
-
- // We already ran the determine_types pass, so we need to run it
- // just for the call statement now. The other types are known.
- call_statement->determine_types();
-
- if (may_call_recover || recover_arg != NULL)
- {
- // Dig up the call expression, which may have been changed
- // during lowering.
- go_assert(call_statement->classification() == STATEMENT_EXPRESSION);
- Expression_statement* es =
- static_cast<Expression_statement*>(call_statement);
- Call_expression* ce = es->expr()->call_expression();
- if (ce == NULL)
- go_assert(saw_errors());
- else
- {
- if (may_call_recover)
- ce->set_is_deferred();
- if (recover_arg != NULL)
- ce->set_recover_arg(recover_arg);
- }
- }
-
- // That is all the thunk has to do.
- gogo->finish_function(location);
-}
-
-// Get the function and argument expressions.
-
-bool
-Thunk_statement::get_fn_and_arg(Expression** pfn, Expression** parg)
-{
- if (this->call_->is_error_expression())
- return false;
-
- Call_expression* ce = this->call_->call_expression();
-
- *pfn = ce->fn();
-
- const Expression_list* args = ce->args();
- if (args == NULL || args->empty())
- *parg = Expression::make_nil(this->location());
- else
- {
- go_assert(args->size() == 1);
- *parg = args->front();
- }
-
- return true;
-}
-
-// Class Go_statement.
-
-Bstatement*
-Go_statement::do_get_backend(Translate_context* context)
-{
- Expression* fn;
- Expression* arg;
- if (!this->get_fn_and_arg(&fn, &arg))
- return context->backend()->error_statement();
-
- Expression* call = Runtime::make_call(Runtime::GO, this->location(), 2,
- fn, arg);
- tree call_tree = call->get_tree(context);
- Bexpression* call_bexpr = tree_to_expr(call_tree);
- return context->backend()->expression_statement(call_bexpr);
-}
-
-// Dump the AST representation for go statement.
-
-void
-Go_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "go ";
- ast_dump_context->dump_expression(this->call());
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a go statement.
-
-Statement*
-Statement::make_go_statement(Call_expression* call, Location location)
-{
- return new Go_statement(call, location);
-}
-
-// Class Defer_statement.
-
-Bstatement*
-Defer_statement::do_get_backend(Translate_context* context)
-{
- Expression* fn;
- Expression* arg;
- if (!this->get_fn_and_arg(&fn, &arg))
- return context->backend()->error_statement();
-
- Location loc = this->location();
- Expression* ds = context->function()->func_value()->defer_stack(loc);
-
- Expression* call = Runtime::make_call(Runtime::DEFER, loc, 3,
- ds, fn, arg);
- tree call_tree = call->get_tree(context);
- Bexpression* call_bexpr = tree_to_expr(call_tree);
- return context->backend()->expression_statement(call_bexpr);
-}
-
-// Dump the AST representation for defer statement.
-
-void
-Defer_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "defer ";
- ast_dump_context->dump_expression(this->call());
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a defer statement.
-
-Statement*
-Statement::make_defer_statement(Call_expression* call,
- Location location)
-{
- return new Defer_statement(call, location);
-}
-
-// Class Return_statement.
-
-// Traverse assignments. We treat each return value as a top level
-// RHS in an expression.
-
-bool
-Return_statement::do_traverse_assignments(Traverse_assignments* tassign)
-{
- Expression_list* vals = this->vals_;
- if (vals != NULL)
- {
- for (Expression_list::iterator p = vals->begin();
- p != vals->end();
- ++p)
- tassign->value(&*p, true, true);
- }
- return true;
-}
-
-// Lower a return statement. If we are returning a function call
-// which returns multiple values which match the current function,
-// split up the call's results. If the return statement lists
-// explicit values, implement this statement by assigning the values
-// to the result variables and change this statement to a naked
-// return. This lets panic/recover work correctly.
-
-Statement*
-Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing,
- Statement_inserter*)
-{
- if (this->is_lowered_)
- return this;
-
- Expression_list* vals = this->vals_;
- this->vals_ = NULL;
- this->is_lowered_ = true;
-
- Location loc = this->location();
-
- size_t vals_count = vals == NULL ? 0 : vals->size();
- Function::Results* results = function->func_value()->result_variables();
- size_t results_count = results == NULL ? 0 : results->size();
-
- if (vals_count == 0)
- {
- if (results_count > 0 && !function->func_value()->results_are_named())
- {
- this->report_error(_("not enough arguments to return"));
- return this;
- }
- return this;
- }
-
- if (results_count == 0)
- {
- this->report_error(_("return with value in function "
- "with no return type"));
- return this;
- }
-
- // If the current function has multiple return values, and we are
- // returning a single call expression, split up the call expression.
- if (results_count > 1
- && vals->size() == 1
- && vals->front()->call_expression() != NULL)
- {
- Call_expression* call = vals->front()->call_expression();
- delete vals;
- vals = new Expression_list;
- for (size_t i = 0; i < results_count; ++i)
- vals->push_back(Expression::make_call_result(call, i));
- vals_count = results_count;
- }
-
- if (vals_count < results_count)
- {
- this->report_error(_("not enough arguments to return"));
- return this;
- }
-
- if (vals_count > results_count)
- {
- this->report_error(_("too many values in return statement"));
- return this;
- }
-
- Block* b = new Block(enclosing, loc);
-
- Expression_list* lhs = new Expression_list();
- Expression_list* rhs = new Expression_list();
-
- Expression_list::const_iterator pe = vals->begin();
- int i = 1;
- for (Function::Results::const_iterator pr = results->begin();
- pr != results->end();
- ++pr, ++pe, ++i)
- {
- Named_object* rv = *pr;
- Expression* e = *pe;
-
- // Check types now so that we give a good error message. The
- // result type is known. We determine the expression type
- // early.
-
- Type *rvtype = rv->result_var_value()->type();
- Type_context type_context(rvtype, false);
- e->determine_type(&type_context);
-
- std::string reason;
- bool ok;
- if (this->are_hidden_fields_ok_)
- ok = Type::are_assignable_hidden_ok(rvtype, e->type(), &reason);
- else
- ok = Type::are_assignable(rvtype, e->type(), &reason);
- if (ok)
- {
- Expression* ve = Expression::make_var_reference(rv, e->location());
- lhs->push_back(ve);
- rhs->push_back(e);
- }
- else
- {
- if (reason.empty())
- error_at(e->location(), "incompatible type for return value %d", i);
- else
- error_at(e->location(),
- "incompatible type for return value %d (%s)",
- i, reason.c_str());
- }
- }
- go_assert(lhs->size() == rhs->size());
-
- if (lhs->empty())
- ;
- else if (lhs->size() == 1)
- {
- Statement* s = Statement::make_assignment(lhs->front(), rhs->front(),
- loc);
- if (this->are_hidden_fields_ok_)
- {
- Assignment_statement* as = static_cast<Assignment_statement*>(s);
- as->set_hidden_fields_are_ok();
- }
- b->add_statement(s);
- delete lhs;
- delete rhs;
- }
- else
- {
- Statement* s = Statement::make_tuple_assignment(lhs, rhs, loc);
- if (this->are_hidden_fields_ok_)
- {
- Tuple_assignment_statement* tas =
- static_cast<Tuple_assignment_statement*>(s);
- tas->set_hidden_fields_are_ok();
- }
- b->add_statement(s);
- }
-
- b->add_statement(this);
-
- delete vals;
-
- return Statement::make_block_statement(b, loc);
-}
-
-// Convert a return statement to the backend representation.
-
-Bstatement*
-Return_statement::do_get_backend(Translate_context* context)
-{
- Location loc = this->location();
-
- Function* function = context->function()->func_value();
- tree fndecl = function->get_decl();
-
- Function::Results* results = function->result_variables();
- std::vector<Bexpression*> retvals;
- if (results != NULL && !results->empty())
- {
- retvals.reserve(results->size());
- for (Function::Results::const_iterator p = results->begin();
- p != results->end();
- p++)
- {
- Expression* vr = Expression::make_var_reference(*p, loc);
- retvals.push_back(tree_to_expr(vr->get_tree(context)));
- }
- }
-
- return context->backend()->return_statement(tree_to_function(fndecl),
- retvals, loc);
-}
-
-// Dump the AST representation for a return statement.
-
-void
-Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "return " ;
- ast_dump_context->dump_expression_list(this->vals_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a return statement.
-
-Return_statement*
-Statement::make_return_statement(Expression_list* vals,
- Location location)
-{
- return new Return_statement(vals, location);
-}
-
-// A break or continue statement.
-
-class Bc_statement : public Statement
-{
- public:
- Bc_statement(bool is_break, Unnamed_label* label, Location location)
- : Statement(STATEMENT_BREAK_OR_CONTINUE, location),
- label_(label), is_break_(is_break)
- { }
-
- bool
- is_break() const
- { return this->is_break_; }
-
- protected:
- int
- do_traverse(Traverse*)
- { return TRAVERSE_CONTINUE; }
-
- bool
- do_may_fall_through() const
- { return false; }
-
- Bstatement*
- do_get_backend(Translate_context* context)
- { return this->label_->get_goto(context, this->location()); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The label that this branches to.
- Unnamed_label* label_;
- // True if this is "break", false if it is "continue".
- bool is_break_;
-};
-
-// Dump the AST representation for a break/continue statement
-
-void
-Bc_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << (this->is_break_ ? "break" : "continue");
- if (this->label_ != NULL)
- {
- ast_dump_context->ostream() << " ";
- ast_dump_context->dump_label_name(this->label_);
- }
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a break statement.
-
-Statement*
-Statement::make_break_statement(Unnamed_label* label, Location location)
-{
- return new Bc_statement(true, label, location);
-}
-
-// Make a continue statement.
-
-Statement*
-Statement::make_continue_statement(Unnamed_label* label,
- Location location)
-{
- return new Bc_statement(false, label, location);
-}
-
-// A goto statement.
-
-class Goto_statement : public Statement
-{
- public:
- Goto_statement(Label* label, Location location)
- : Statement(STATEMENT_GOTO, location),
- label_(label)
- { }
-
- protected:
- int
- do_traverse(Traverse*)
- { return TRAVERSE_CONTINUE; }
-
- void
- do_check_types(Gogo*);
-
- bool
- do_may_fall_through() const
- { return false; }
-
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- Label* label_;
-};
-
-// Check types for a label. There aren't any types per se, but we use
-// this to give an error if the label was never defined.
-
-void
-Goto_statement::do_check_types(Gogo*)
-{
- if (!this->label_->is_defined())
- {
- error_at(this->location(), "reference to undefined label %qs",
- Gogo::message_name(this->label_->name()).c_str());
- this->set_is_error();
- }
-}
-
-// Convert the goto statement to the backend representation.
-
-Bstatement*
-Goto_statement::do_get_backend(Translate_context* context)
-{
- Blabel* blabel = this->label_->get_backend_label(context);
- return context->backend()->goto_statement(blabel, this->location());
-}
-
-// Dump the AST representation for a goto statement.
-
-void
-Goto_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "goto " << this->label_->name() << std::endl;
-}
-
-// Make a goto statement.
-
-Statement*
-Statement::make_goto_statement(Label* label, Location location)
-{
- return new Goto_statement(label, location);
-}
-
-// A goto statement to an unnamed label.
-
-class Goto_unnamed_statement : public Statement
-{
- public:
- Goto_unnamed_statement(Unnamed_label* label, Location location)
- : Statement(STATEMENT_GOTO_UNNAMED, location),
- label_(label)
- { }
-
- protected:
- int
- do_traverse(Traverse*)
- { return TRAVERSE_CONTINUE; }
-
- bool
- do_may_fall_through() const
- { return false; }
-
- Bstatement*
- do_get_backend(Translate_context* context)
- { return this->label_->get_goto(context, this->location()); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- Unnamed_label* label_;
-};
-
-// Dump the AST representation for an unnamed goto statement
-
-void
-Goto_unnamed_statement::do_dump_statement(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "goto ";
- ast_dump_context->dump_label_name(this->label_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a goto statement to an unnamed label.
-
-Statement*
-Statement::make_goto_unnamed_statement(Unnamed_label* label,
- Location location)
-{
- return new Goto_unnamed_statement(label, location);
-}
-
-// Class Label_statement.
-
-// Traversal.
-
-int
-Label_statement::do_traverse(Traverse*)
-{
- return TRAVERSE_CONTINUE;
-}
-
-// Return the backend representation of the statement defining this
-// label.
-
-Bstatement*
-Label_statement::do_get_backend(Translate_context* context)
-{
- Blabel* blabel = this->label_->get_backend_label(context);
- return context->backend()->label_definition_statement(blabel);
-}
-
-// Dump the AST for a label definition statement.
-
-void
-Label_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << this->label_->name() << ":" << std::endl;
-}
-
-// Make a label statement.
-
-Statement*
-Statement::make_label_statement(Label* label, Location location)
-{
- return new Label_statement(label, location);
-}
-
-// An unnamed label statement.
-
-class Unnamed_label_statement : public Statement
-{
- public:
- Unnamed_label_statement(Unnamed_label* label)
- : Statement(STATEMENT_UNNAMED_LABEL, label->location()),
- label_(label)
- { }
-
- protected:
- int
- do_traverse(Traverse*)
- { return TRAVERSE_CONTINUE; }
-
- Bstatement*
- do_get_backend(Translate_context* context)
- { return this->label_->get_definition(context); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The label.
- Unnamed_label* label_;
-};
-
-// Dump the AST representation for an unnamed label definition statement.
-
-void
-Unnamed_label_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
- const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_label_name(this->label_);
- ast_dump_context->ostream() << ":" << std::endl;
-}
-
-// Make an unnamed label statement.
-
-Statement*
-Statement::make_unnamed_label_statement(Unnamed_label* label)
-{
- return new Unnamed_label_statement(label);
-}
-
-// An if statement.
-
-class If_statement : public Statement
-{
- public:
- If_statement(Expression* cond, Block* then_block, Block* else_block,
- Location location)
- : Statement(STATEMENT_IF, location),
- cond_(cond), then_block_(then_block), else_block_(else_block)
- { }
-
- protected:
- int
- do_traverse(Traverse*);
-
- void
- do_determine_types();
-
- void
- do_check_types(Gogo*);
-
- bool
- do_may_fall_through() const;
-
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- Expression* cond_;
- Block* then_block_;
- Block* else_block_;
-};
-
-// Traversal.
-
-int
-If_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT
- || this->then_block_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (this->else_block_ != NULL)
- {
- if (this->else_block_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-void
-If_statement::do_determine_types()
-{
- Type_context context(Type::lookup_bool_type(), false);
- this->cond_->determine_type(&context);
- this->then_block_->determine_types();
- if (this->else_block_ != NULL)
- this->else_block_->determine_types();
-}
-
-// Check types.
-
-void
-If_statement::do_check_types(Gogo*)
-{
- Type* type = this->cond_->type();
- if (type->is_error())
- this->set_is_error();
- else if (!type->is_boolean_type())
- this->report_error(_("expected boolean expression"));
-}
-
-// Whether the overall statement may fall through.
-
-bool
-If_statement::do_may_fall_through() const
-{
- return (this->else_block_ == NULL
- || this->then_block_->may_fall_through()
- || this->else_block_->may_fall_through());
-}
-
-// Get the backend representation.
-
-Bstatement*
-If_statement::do_get_backend(Translate_context* context)
-{
- go_assert(this->cond_->type()->is_boolean_type()
- || this->cond_->type()->is_error());
- tree cond_tree = this->cond_->get_tree(context);
- Bexpression* cond_expr = tree_to_expr(cond_tree);
- Bblock* then_block = this->then_block_->get_backend(context);
- Bblock* else_block = (this->else_block_ == NULL
- ? NULL
- : this->else_block_->get_backend(context));
- return context->backend()->if_statement(cond_expr, then_block,
- else_block, this->location());
-}
-
-// Dump the AST representation for an if statement
-
-void
-If_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "if ";
- ast_dump_context->dump_expression(this->cond_);
- ast_dump_context->ostream() << std::endl;
- if (ast_dump_context->dump_subblocks())
- {
- ast_dump_context->dump_block(this->then_block_);
- if (this->else_block_ != NULL)
- {
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "else" << std::endl;
- ast_dump_context->dump_block(this->else_block_);
- }
- }
-}
-
-// Make an if statement.
-
-Statement*
-Statement::make_if_statement(Expression* cond, Block* then_block,
- Block* else_block, Location location)
-{
- return new If_statement(cond, then_block, else_block, location);
-}
-
-// Class Case_clauses::Hash_integer_value.
-
-class Case_clauses::Hash_integer_value
-{
- public:
- size_t
- operator()(Expression*) const;
-};
-
-size_t
-Case_clauses::Hash_integer_value::operator()(Expression* pe) const
-{
- Numeric_constant nc;
- mpz_t ival;
- if (!pe->numeric_constant_value(&nc) || !nc.to_int(&ival))
- go_unreachable();
- size_t ret = mpz_get_ui(ival);
- mpz_clear(ival);
- return ret;
-}
-
-// Class Case_clauses::Eq_integer_value.
-
-class Case_clauses::Eq_integer_value
-{
- public:
- bool
- operator()(Expression*, Expression*) const;
-};
-
-bool
-Case_clauses::Eq_integer_value::operator()(Expression* a, Expression* b) const
-{
- Numeric_constant anc;
- mpz_t aval;
- Numeric_constant bnc;
- mpz_t bval;
- if (!a->numeric_constant_value(&anc)
- || !anc.to_int(&aval)
- || !b->numeric_constant_value(&bnc)
- || !bnc.to_int(&bval))
- go_unreachable();
- bool ret = mpz_cmp(aval, bval) == 0;
- mpz_clear(aval);
- mpz_clear(bval);
- return ret;
-}
-
-// Class Case_clauses::Case_clause.
-
-// Traversal.
-
-int
-Case_clauses::Case_clause::traverse(Traverse* traverse)
-{
- if (this->cases_ != NULL
- && (traverse->traverse_mask()
- & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
- {
- if (this->cases_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- if (this->statements_ != NULL)
- {
- if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Check whether all the case expressions are integer constants.
-
-bool
-Case_clauses::Case_clause::is_constant() const
-{
- if (this->cases_ != NULL)
- {
- for (Expression_list::const_iterator p = this->cases_->begin();
- p != this->cases_->end();
- ++p)
- if (!(*p)->is_constant() || (*p)->type()->integer_type() == NULL)
- return false;
- }
- return true;
-}
-
-// Lower a case clause for a nonconstant switch. VAL_TEMP is the
-// value we are switching on; it may be NULL. If START_LABEL is not
-// NULL, it goes at the start of the statements, after the condition
-// test. We branch to FINISH_LABEL at the end of the statements.
-
-void
-Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp,
- Unnamed_label* start_label,
- Unnamed_label* finish_label) const
-{
- Location loc = this->location_;
- Unnamed_label* next_case_label;
- if (this->cases_ == NULL || this->cases_->empty())
- {
- go_assert(this->is_default_);
- next_case_label = NULL;
- }
- else
- {
- Expression* cond = NULL;
-
- for (Expression_list::const_iterator p = this->cases_->begin();
- p != this->cases_->end();
- ++p)
- {
- Expression* ref = Expression::make_temporary_reference(val_temp,
- loc);
- Expression* this_cond = Expression::make_binary(OPERATOR_EQEQ, ref,
- *p, loc);
- if (cond == NULL)
- cond = this_cond;
- else
- cond = Expression::make_binary(OPERATOR_OROR, cond, this_cond, loc);
- }
-
- Block* then_block = new Block(b, loc);
- next_case_label = new Unnamed_label(Linemap::unknown_location());
- Statement* s = Statement::make_goto_unnamed_statement(next_case_label,
- loc);
- then_block->add_statement(s);
-
- // if !COND { goto NEXT_CASE_LABEL }
- cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
- s = Statement::make_if_statement(cond, then_block, NULL, loc);
- b->add_statement(s);
- }
-
- if (start_label != NULL)
- b->add_statement(Statement::make_unnamed_label_statement(start_label));
-
- if (this->statements_ != NULL)
- b->add_statement(Statement::make_block_statement(this->statements_, loc));
-
- Statement* s = Statement::make_goto_unnamed_statement(finish_label, loc);
- b->add_statement(s);
-
- if (next_case_label != NULL)
- b->add_statement(Statement::make_unnamed_label_statement(next_case_label));
-}
-
-// Determine types.
-
-void
-Case_clauses::Case_clause::determine_types(Type* type)
-{
- if (this->cases_ != NULL)
- {
- Type_context case_context(type, false);
- for (Expression_list::iterator p = this->cases_->begin();
- p != this->cases_->end();
- ++p)
- (*p)->determine_type(&case_context);
- }
- if (this->statements_ != NULL)
- this->statements_->determine_types();
-}
-
-// Check types. Returns false if there was an error.
-
-bool
-Case_clauses::Case_clause::check_types(Type* type)
-{
- if (this->cases_ != NULL)
- {
- for (Expression_list::iterator p = this->cases_->begin();
- p != this->cases_->end();
- ++p)
- {
- if (!Type::are_assignable(type, (*p)->type(), NULL)
- && !Type::are_assignable((*p)->type(), type, NULL))
- {
- error_at((*p)->location(),
- "type mismatch between switch value and case clause");
- return false;
- }
- }
- }
- return true;
-}
-
-// Return true if this clause may fall through to the following
-// statements. Note that this is not the same as whether the case
-// uses the "fallthrough" keyword.
-
-bool
-Case_clauses::Case_clause::may_fall_through() const
-{
- if (this->statements_ == NULL)
- return true;
- return this->statements_->may_fall_through();
-}
-
-// Convert the case values and statements to the backend
-// representation. BREAK_LABEL is the label which break statements
-// should branch to. CASE_CONSTANTS is used to detect duplicate
-// constants. *CASES should be passed as an empty vector; the values
-// for this case will be added to it. If this is the default case,
-// *CASES will remain empty. This returns the statement to execute if
-// one of these cases is selected.
-
-Bstatement*
-Case_clauses::Case_clause::get_backend(Translate_context* context,
- Unnamed_label* break_label,
- Case_constants* case_constants,
- std::vector<Bexpression*>* cases) const
-{
- if (this->cases_ != NULL)
- {
- go_assert(!this->is_default_);
- for (Expression_list::const_iterator p = this->cases_->begin();
- p != this->cases_->end();
- ++p)
- {
- Expression* e = *p;
- if (e->classification() != Expression::EXPRESSION_INTEGER)
- {
- Numeric_constant nc;
- mpz_t ival;
- if (!(*p)->numeric_constant_value(&nc) || !nc.to_int(&ival))
- {
- // Something went wrong. This can happen with a
- // negative constant and an unsigned switch value.
- go_assert(saw_errors());
- continue;
- }
- go_assert(nc.type() != NULL);
- e = Expression::make_integer(&ival, nc.type(), e->location());
- mpz_clear(ival);
- }
-
- std::pair<Case_constants::iterator, bool> ins =
- case_constants->insert(e);
- if (!ins.second)
- {
- // Value was already present.
- error_at(this->location_, "duplicate case in switch");
- e = Expression::make_error(this->location_);
- }
-
- tree case_tree = e->get_tree(context);
- Bexpression* case_expr = tree_to_expr(case_tree);
- cases->push_back(case_expr);
- }
- }
-
- Bstatement* statements;
- if (this->statements_ == NULL)
- statements = NULL;
- else
- {
- Bblock* bblock = this->statements_->get_backend(context);
- statements = context->backend()->block_statement(bblock);
- }
-
- Bstatement* break_stat;
- if (this->is_fallthrough_)
- break_stat = NULL;
- else
- break_stat = break_label->get_goto(context, this->location_);
-
- if (statements == NULL)
- return break_stat;
- else if (break_stat == NULL)
- return statements;
- else
- return context->backend()->compound_statement(statements, break_stat);
-}
-
-// Dump the AST representation for a case clause
-
-void
-Case_clauses::Case_clause::dump_clause(Ast_dump_context* ast_dump_context)
- const
-{
- ast_dump_context->print_indent();
- if (this->is_default_)
- {
- ast_dump_context->ostream() << "default:";
- }
- else
- {
- ast_dump_context->ostream() << "case ";
- ast_dump_context->dump_expression_list(this->cases_);
- ast_dump_context->ostream() << ":" ;
- }
- ast_dump_context->dump_block(this->statements_);
- if (this->is_fallthrough_)
- {
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << " (fallthrough)" << std::endl;
- }
-}
-
-// Class Case_clauses.
-
-// Traversal.
-
-int
-Case_clauses::traverse(Traverse* traverse)
-{
- for (Clauses::iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- {
- if (p->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Check whether all the case expressions are constant.
-
-bool
-Case_clauses::is_constant() const
-{
- for (Clauses::const_iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- if (!p->is_constant())
- return false;
- return true;
-}
-
-// Lower case clauses for a nonconstant switch.
-
-void
-Case_clauses::lower(Block* b, Temporary_statement* val_temp,
- Unnamed_label* break_label) const
-{
- // The default case.
- const Case_clause* default_case = NULL;
-
- // The label for the fallthrough of the previous case.
- Unnamed_label* last_fallthrough_label = NULL;
-
- // The label for the start of the default case. This is used if the
- // case before the default case falls through.
- Unnamed_label* default_start_label = NULL;
-
- // The label for the end of the default case. This normally winds
- // up as BREAK_LABEL, but it will be different if the default case
- // falls through.
- Unnamed_label* default_finish_label = NULL;
-
- for (Clauses::const_iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- {
- // The label to use for the start of the statements for this
- // case. This is NULL unless the previous case falls through.
- Unnamed_label* start_label = last_fallthrough_label;
-
- // The label to jump to after the end of the statements for this
- // case.
- Unnamed_label* finish_label = break_label;
-
- last_fallthrough_label = NULL;
- if (p->is_fallthrough() && p + 1 != this->clauses_.end())
- {
- finish_label = new Unnamed_label(p->location());
- last_fallthrough_label = finish_label;
- }
-
- if (!p->is_default())
- p->lower(b, val_temp, start_label, finish_label);
- else
- {
- // We have to move the default case to the end, so that we
- // only use it if all the other tests fail.
- default_case = &*p;
- default_start_label = start_label;
- default_finish_label = finish_label;
- }
- }
-
- if (default_case != NULL)
- default_case->lower(b, val_temp, default_start_label,
- default_finish_label);
-}
-
-// Determine types.
-
-void
-Case_clauses::determine_types(Type* type)
-{
- for (Clauses::iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- p->determine_types(type);
-}
-
-// Check types. Returns false if there was an error.
-
-bool
-Case_clauses::check_types(Type* type)
-{
- bool ret = true;
- for (Clauses::iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- {
- if (!p->check_types(type))
- ret = false;
- }
- return ret;
-}
-
-// Return true if these clauses may fall through to the statements
-// following the switch statement.
-
-bool
-Case_clauses::may_fall_through() const
-{
- bool found_default = false;
- for (Clauses::const_iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- {
- if (p->may_fall_through() && !p->is_fallthrough())
- return true;
- if (p->is_default())
- found_default = true;
- }
- return !found_default;
-}
-
-// Convert the cases to the backend representation. This sets
-// *ALL_CASES and *ALL_STATEMENTS.
-
-void
-Case_clauses::get_backend(Translate_context* context,
- Unnamed_label* break_label,
- std::vector<std::vector<Bexpression*> >* all_cases,
- std::vector<Bstatement*>* all_statements) const
-{
- Case_constants case_constants;
-
- size_t c = this->clauses_.size();
- all_cases->resize(c);
- all_statements->resize(c);
-
- size_t i = 0;
- for (Clauses::const_iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p, ++i)
- {
- std::vector<Bexpression*> cases;
- Bstatement* stat = p->get_backend(context, break_label, &case_constants,
- &cases);
- (*all_cases)[i].swap(cases);
- (*all_statements)[i] = stat;
- }
-}
-
-// Dump the AST representation for case clauses (from a switch statement)
-
-void
-Case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
-{
- for (Clauses::const_iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- p->dump_clause(ast_dump_context);
-}
-
-// A constant switch statement. A Switch_statement is lowered to this
-// when all the cases are constants.
-
-class Constant_switch_statement : public Statement
-{
- public:
- Constant_switch_statement(Expression* val, Case_clauses* clauses,
- Unnamed_label* break_label,
- Location location)
- : Statement(STATEMENT_CONSTANT_SWITCH, location),
- val_(val), clauses_(clauses), break_label_(break_label)
- { }
-
- protected:
- int
- do_traverse(Traverse*);
-
- void
- do_determine_types();
-
- void
- do_check_types(Gogo*);
-
- bool
- do_may_fall_through() const;
-
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The value to switch on.
- Expression* val_;
- // The case clauses.
- Case_clauses* clauses_;
- // The break label, if needed.
- Unnamed_label* break_label_;
-};
-
-// Traversal.
-
-int
-Constant_switch_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return this->clauses_->traverse(traverse);
-}
-
-// Determine types.
-
-void
-Constant_switch_statement::do_determine_types()
-{
- this->val_->determine_type_no_context();
- this->clauses_->determine_types(this->val_->type());
-}
-
-// Check types.
-
-void
-Constant_switch_statement::do_check_types(Gogo*)
-{
- if (!this->clauses_->check_types(this->val_->type()))
- this->set_is_error();
-}
-
-// Return whether this switch may fall through.
-
-bool
-Constant_switch_statement::do_may_fall_through() const
-{
- if (this->clauses_ == NULL)
- return true;
-
- // If we have a break label, then some case needed it. That implies
- // that the switch statement as a whole can fall through.
- if (this->break_label_ != NULL)
- return true;
-
- return this->clauses_->may_fall_through();
-}
-
-// Convert to GENERIC.
-
-Bstatement*
-Constant_switch_statement::do_get_backend(Translate_context* context)
-{
- tree switch_val_tree = this->val_->get_tree(context);
- Bexpression* switch_val_expr = tree_to_expr(switch_val_tree);
-
- Unnamed_label* break_label = this->break_label_;
- if (break_label == NULL)
- break_label = new Unnamed_label(this->location());
-
- std::vector<std::vector<Bexpression*> > all_cases;
- std::vector<Bstatement*> all_statements;
- this->clauses_->get_backend(context, break_label, &all_cases,
- &all_statements);
-
- Bstatement* switch_statement;
- switch_statement = context->backend()->switch_statement(switch_val_expr,
- all_cases,
- all_statements,
- this->location());
- Bstatement* ldef = break_label->get_definition(context);
- return context->backend()->compound_statement(switch_statement, ldef);
-}
-
-// Dump the AST representation for a constant switch statement.
-
-void
-Constant_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
- const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "switch ";
- ast_dump_context->dump_expression(this->val_);
-
- if (ast_dump_context->dump_subblocks())
- {
- ast_dump_context->ostream() << " {" << std::endl;
- this->clauses_->dump_clauses(ast_dump_context);
- ast_dump_context->ostream() << "}";
- }
-
- ast_dump_context->ostream() << std::endl;
-}
-
-// Class Switch_statement.
-
-// Traversal.
-
-int
-Switch_statement::do_traverse(Traverse* traverse)
-{
- if (this->val_ != NULL)
- {
- if (this->traverse_expression(traverse, &this->val_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return this->clauses_->traverse(traverse);
-}
-
-// Lower a Switch_statement to a Constant_switch_statement or a series
-// of if statements.
-
-Statement*
-Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
- Statement_inserter*)
-{
- Location loc = this->location();
-
- if (this->val_ != NULL
- && (this->val_->is_error_expression()
- || this->val_->type()->is_error()))
- return Statement::make_error_statement(loc);
-
- if (this->val_ != NULL
- && this->val_->type()->integer_type() != NULL
- && !this->clauses_->empty()
- && this->clauses_->is_constant())
- return new Constant_switch_statement(this->val_, this->clauses_,
- this->break_label_, loc);
-
- if (this->val_ != NULL
- && !this->val_->type()->is_comparable()
- && !Type::are_compatible_for_comparison(true, this->val_->type(),
- Type::make_nil_type(), NULL))
- {
- error_at(this->val_->location(),
- "cannot switch on value whose type that may not be compared");
- return Statement::make_error_statement(loc);
- }
-
- Block* b = new Block(enclosing, loc);
-
- if (this->clauses_->empty())
- {
- Expression* val = this->val_;
- if (val == NULL)
- val = Expression::make_boolean(true, loc);
- return Statement::make_statement(val, true);
- }
-
- // var val_temp VAL_TYPE = VAL
- Expression* val = this->val_;
- if (val == NULL)
- val = Expression::make_boolean(true, loc);
- Temporary_statement* val_temp = Statement::make_temporary(NULL, val, loc);
- b->add_statement(val_temp);
-
- this->clauses_->lower(b, val_temp, this->break_label());
-
- Statement* s = Statement::make_unnamed_label_statement(this->break_label_);
- b->add_statement(s);
-
- return Statement::make_block_statement(b, loc);
-}
-
-// Return the break label for this switch statement, creating it if
-// necessary.
-
-Unnamed_label*
-Switch_statement::break_label()
-{
- if (this->break_label_ == NULL)
- this->break_label_ = new Unnamed_label(this->location());
- return this->break_label_;
-}
-
-// Dump the AST representation for a switch statement.
-
-void
-Switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "switch ";
- if (this->val_ != NULL)
- {
- ast_dump_context->dump_expression(this->val_);
- }
- if (ast_dump_context->dump_subblocks())
- {
- ast_dump_context->ostream() << " {" << std::endl;
- this->clauses_->dump_clauses(ast_dump_context);
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "}";
- }
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a switch statement.
-
-Switch_statement*
-Statement::make_switch_statement(Expression* val, Location location)
-{
- return new Switch_statement(val, location);
-}
-
-// Class Type_case_clauses::Type_case_clause.
-
-// Traversal.
-
-int
-Type_case_clauses::Type_case_clause::traverse(Traverse* traverse)
-{
- if (!this->is_default_
- && ((traverse->traverse_mask()
- & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
- && Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (this->statements_ != NULL)
- return this->statements_->traverse(traverse);
- return TRAVERSE_CONTINUE;
-}
-
-// Lower one clause in a type switch. Add statements to the block B.
-// The type descriptor we are switching on is in DESCRIPTOR_TEMP.
-// BREAK_LABEL is the label at the end of the type switch.
-// *STMTS_LABEL, if not NULL, is a label to put at the start of the
-// statements.
-
-void
-Type_case_clauses::Type_case_clause::lower(Type* switch_val_type,
- Block* b,
- Temporary_statement* descriptor_temp,
- Unnamed_label* break_label,
- Unnamed_label** stmts_label) const
-{
- Location loc = this->location_;
-
- Unnamed_label* next_case_label = NULL;
- if (!this->is_default_)
- {
- Type* type = this->type_;
-
- std::string reason;
- if (switch_val_type->interface_type() != NULL
- && !type->is_nil_constant_as_type()
- && type->interface_type() == NULL
- && !switch_val_type->interface_type()->implements_interface(type,
- &reason))
- {
- if (reason.empty())
- error_at(this->location_, "impossible type switch case");
- else
- error_at(this->location_, "impossible type switch case (%s)",
- reason.c_str());
- }
-
- Expression* ref = Expression::make_temporary_reference(descriptor_temp,
- loc);
-
- Expression* cond;
- // The language permits case nil, which is of course a constant
- // rather than a type. It will appear here as an invalid
- // forwarding type.
- if (type->is_nil_constant_as_type())
- cond = Expression::make_binary(OPERATOR_EQEQ, ref,
- Expression::make_nil(loc),
- loc);
- else
- cond = Runtime::make_call((type->interface_type() == NULL
- ? Runtime::IFACETYPEEQ
- : Runtime::IFACEI2TP),
- loc, 2,
- Expression::make_type_descriptor(type, loc),
- ref);
-
- Unnamed_label* dest;
- if (!this->is_fallthrough_)
- {
- // if !COND { goto NEXT_CASE_LABEL }
- next_case_label = new Unnamed_label(Linemap::unknown_location());
- dest = next_case_label;
- cond = Expression::make_unary(OPERATOR_NOT, cond, loc);
- }
- else
- {
- // if COND { goto STMTS_LABEL }
- go_assert(stmts_label != NULL);
- if (*stmts_label == NULL)
- *stmts_label = new Unnamed_label(Linemap::unknown_location());
- dest = *stmts_label;
- }
- Block* then_block = new Block(b, loc);
- Statement* s = Statement::make_goto_unnamed_statement(dest, loc);
- then_block->add_statement(s);
- s = Statement::make_if_statement(cond, then_block, NULL, loc);
- b->add_statement(s);
- }
-
- if (this->statements_ != NULL
- || (!this->is_fallthrough_
- && stmts_label != NULL
- && *stmts_label != NULL))
- {
- go_assert(!this->is_fallthrough_);
- if (stmts_label != NULL && *stmts_label != NULL)
- {
- go_assert(!this->is_default_);
- if (this->statements_ != NULL)
- (*stmts_label)->set_location(this->statements_->start_location());
- Statement* s = Statement::make_unnamed_label_statement(*stmts_label);
- b->add_statement(s);
- *stmts_label = NULL;
- }
- if (this->statements_ != NULL)
- b->add_statement(Statement::make_block_statement(this->statements_,
- loc));
- }
-
- if (this->is_fallthrough_)
- go_assert(next_case_label == NULL);
- else
- {
- Location gloc = (this->statements_ == NULL
- ? loc
- : this->statements_->end_location());
- b->add_statement(Statement::make_goto_unnamed_statement(break_label,
- gloc));
- if (next_case_label != NULL)
- {
- Statement* s =
- Statement::make_unnamed_label_statement(next_case_label);
- b->add_statement(s);
- }
- }
-}
-
-// Dump the AST representation for a type case clause
-
-void
-Type_case_clauses::Type_case_clause::dump_clause(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- if (this->is_default_)
- {
- ast_dump_context->ostream() << "default:";
- }
- else
- {
- ast_dump_context->ostream() << "case ";
- ast_dump_context->dump_type(this->type_);
- ast_dump_context->ostream() << ":" ;
- }
- ast_dump_context->dump_block(this->statements_);
- if (this->is_fallthrough_)
- {
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << " (fallthrough)" << std::endl;
- }
-}
-
-// Class Type_case_clauses.
-
-// Traversal.
-
-int
-Type_case_clauses::traverse(Traverse* traverse)
-{
- for (Type_clauses::iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- {
- if (p->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Check for duplicate types.
-
-void
-Type_case_clauses::check_duplicates() const
-{
- typedef Unordered_set_hash(const Type*, Type_hash_identical,
- Type_identical) Types_seen;
- Types_seen types_seen;
- for (Type_clauses::const_iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- {
- Type* t = p->type();
- if (t == NULL)
- continue;
- if (t->is_nil_constant_as_type())
- t = Type::make_nil_type();
- std::pair<Types_seen::iterator, bool> ins = types_seen.insert(t);
- if (!ins.second)
- error_at(p->location(), "duplicate type in switch");
- }
-}
-
-// Lower the clauses in a type switch. Add statements to the block B.
-// The type descriptor we are switching on is in DESCRIPTOR_TEMP.
-// BREAK_LABEL is the label at the end of the type switch.
-
-void
-Type_case_clauses::lower(Type* switch_val_type, Block* b,
- Temporary_statement* descriptor_temp,
- Unnamed_label* break_label) const
-{
- const Type_case_clause* default_case = NULL;
-
- Unnamed_label* stmts_label = NULL;
- for (Type_clauses::const_iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- {
- if (!p->is_default())
- p->lower(switch_val_type, b, descriptor_temp, break_label,
- &stmts_label);
- else
- {
- // We are generating a series of tests, which means that we
- // need to move the default case to the end.
- default_case = &*p;
- }
- }
- go_assert(stmts_label == NULL);
-
- if (default_case != NULL)
- default_case->lower(switch_val_type, b, descriptor_temp, break_label,
- NULL);
-}
-
-// Dump the AST representation for case clauses (from a switch statement)
-
-void
-Type_case_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
-{
- for (Type_clauses::const_iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- p->dump_clause(ast_dump_context);
-}
-
-// Class Type_switch_statement.
-
-// Traversal.
-
-int
-Type_switch_statement::do_traverse(Traverse* traverse)
-{
- if (this->var_ == NULL)
- {
- if (this->traverse_expression(traverse, &this->expr_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- if (this->clauses_ != NULL)
- return this->clauses_->traverse(traverse);
- return TRAVERSE_CONTINUE;
-}
-
-// Lower a type switch statement to a series of if statements. The gc
-// compiler is able to generate a table in some cases. However, that
-// does not work for us because we may have type descriptors in
-// different shared libraries, so we can't compare them with simple
-// equality testing.
-
-Statement*
-Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
- Statement_inserter*)
-{
- const Location loc = this->location();
-
- if (this->clauses_ != NULL)
- this->clauses_->check_duplicates();
-
- Block* b = new Block(enclosing, loc);
-
- Type* val_type = (this->var_ != NULL
- ? this->var_->var_value()->type()
- : this->expr_->type());
-
- if (val_type->interface_type() == NULL)
- {
- if (!val_type->is_error())
- this->report_error(_("cannot type switch on non-interface value"));
- return Statement::make_error_statement(loc);
- }
-
- // var descriptor_temp DESCRIPTOR_TYPE
- Type* descriptor_type = Type::make_type_descriptor_ptr_type();
- Temporary_statement* descriptor_temp =
- Statement::make_temporary(descriptor_type, NULL, loc);
- b->add_statement(descriptor_temp);
-
- // descriptor_temp = ifacetype(val_temp) FIXME: This should be
- // inlined.
- bool is_empty = val_type->interface_type()->is_empty();
- Expression* ref;
- if (this->var_ == NULL)
- ref = this->expr_;
- else
- ref = Expression::make_var_reference(this->var_, loc);
- Expression* call = Runtime::make_call((is_empty
- ? Runtime::EFACETYPE
- : Runtime::IFACETYPE),
- loc, 1, ref);
- Temporary_reference_expression* lhs =
- Expression::make_temporary_reference(descriptor_temp, loc);
- lhs->set_is_lvalue();
- Statement* s = Statement::make_assignment(lhs, call, loc);
- b->add_statement(s);
-
- if (this->clauses_ != NULL)
- this->clauses_->lower(val_type, b, descriptor_temp, this->break_label());
-
- s = Statement::make_unnamed_label_statement(this->break_label_);
- b->add_statement(s);
-
- return Statement::make_block_statement(b, loc);
-}
-
-// Return the break label for this type switch statement, creating it
-// if necessary.
-
-Unnamed_label*
-Type_switch_statement::break_label()
-{
- if (this->break_label_ == NULL)
- this->break_label_ = new Unnamed_label(this->location());
- return this->break_label_;
-}
-
-// Dump the AST representation for a type switch statement
-
-void
-Type_switch_statement::do_dump_statement(Ast_dump_context* ast_dump_context)
- const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "switch " << this->var_->name() << " = ";
- ast_dump_context->dump_expression(this->expr_);
- ast_dump_context->ostream() << " .(type)";
- if (ast_dump_context->dump_subblocks())
- {
- ast_dump_context->ostream() << " {" << std::endl;
- this->clauses_->dump_clauses(ast_dump_context);
- ast_dump_context->ostream() << "}";
- }
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a type switch statement.
-
-Type_switch_statement*
-Statement::make_type_switch_statement(Named_object* var, Expression* expr,
- Location location)
-{
- return new Type_switch_statement(var, expr, location);
-}
-
-// Class Send_statement.
-
-// Traversal.
-
-int
-Send_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression(traverse, &this->channel_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return this->traverse_expression(traverse, &this->val_);
-}
-
-// Determine types.
-
-void
-Send_statement::do_determine_types()
-{
- this->channel_->determine_type_no_context();
- Type* type = this->channel_->type();
- Type_context context;
- if (type->channel_type() != NULL)
- context.type = type->channel_type()->element_type();
- this->val_->determine_type(&context);
-}
-
-// Check types.
-
-void
-Send_statement::do_check_types(Gogo*)
-{
- Type* type = this->channel_->type();
- if (type->is_error())
- {
- this->set_is_error();
- return;
- }
- Channel_type* channel_type = type->channel_type();
- if (channel_type == NULL)
- {
- error_at(this->location(), "left operand of %<<-%> must be channel");
- this->set_is_error();
- return;
- }
- Type* element_type = channel_type->element_type();
- if (!Type::are_assignable(element_type, this->val_->type(), NULL))
- {
- this->report_error(_("incompatible types in send"));
- return;
- }
- if (!channel_type->may_send())
- {
- this->report_error(_("invalid send on receive-only channel"));
- return;
- }
-}
-
-// Convert a send statement to the backend representation.
-
-Bstatement*
-Send_statement::do_get_backend(Translate_context* context)
-{
- Location loc = this->location();
-
- Channel_type* channel_type = this->channel_->type()->channel_type();
- Type* element_type = channel_type->element_type();
- Expression* val = Expression::make_cast(element_type, this->val_, loc);
-
- bool is_small;
- bool can_take_address;
- switch (element_type->base()->classification())
- {
- case Type::TYPE_BOOLEAN:
- case Type::TYPE_INTEGER:
- case Type::TYPE_FUNCTION:
- case Type::TYPE_POINTER:
- case Type::TYPE_MAP:
- case Type::TYPE_CHANNEL:
- is_small = true;
- can_take_address = false;
- break;
-
- case Type::TYPE_FLOAT:
- case Type::TYPE_COMPLEX:
- case Type::TYPE_STRING:
- case Type::TYPE_INTERFACE:
- is_small = false;
- can_take_address = false;
- break;
-
- case Type::TYPE_STRUCT:
- is_small = false;
- can_take_address = true;
- break;
-
- case Type::TYPE_ARRAY:
- is_small = false;
- can_take_address = !element_type->is_slice_type();
- break;
-
- default:
- case Type::TYPE_ERROR:
- case Type::TYPE_VOID:
- case Type::TYPE_SINK:
- case Type::TYPE_NIL:
- case Type::TYPE_NAMED:
- case Type::TYPE_FORWARD:
- go_assert(saw_errors());
- return context->backend()->error_statement();
- }
-
- // Only try to take the address of a variable. We have already
- // moved variables to the heap, so this should not cause that to
- // happen unnecessarily.
- if (can_take_address
- && val->var_expression() == NULL
- && val->temporary_reference_expression() == NULL)
- can_take_address = false;
-
- Expression* td = Expression::make_type_descriptor(this->channel_->type(),
- loc);
-
- Runtime::Function code;
- Bstatement* btemp = NULL;
- if (is_small)
- {
- // Type is small enough to handle as uint64.
- code = Runtime::SEND_SMALL;
- val = Expression::make_unsafe_cast(Type::lookup_integer_type("uint64"),
- val, loc);
- }
- else if (can_take_address)
- {
- // Must pass address of value. The function doesn't change the
- // value, so just take its address directly.
- code = Runtime::SEND_BIG;
- val = Expression::make_unary(OPERATOR_AND, val, loc);
- }
- else
- {
- // Must pass address of value, but the value is small enough
- // that it might be in registers. Copy value into temporary
- // variable to take address.
- code = Runtime::SEND_BIG;
- Temporary_statement* temp = Statement::make_temporary(element_type,
- val, loc);
- Expression* ref = Expression::make_temporary_reference(temp, loc);
- val = Expression::make_unary(OPERATOR_AND, ref, loc);
- btemp = temp->get_backend(context);
- }
-
- Expression* call = Runtime::make_call(code, loc, 3, td, this->channel_, val);
-
- context->gogo()->lower_expression(context->function(), NULL, &call);
- Bexpression* bcall = tree_to_expr(call->get_tree(context));
- Bstatement* s = context->backend()->expression_statement(bcall);
-
- if (btemp == NULL)
- return s;
- else
- return context->backend()->compound_statement(btemp, s);
-}
-
-// Dump the AST representation for a send statement
-
-void
-Send_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->dump_expression(this->channel_);
- ast_dump_context->ostream() << " <- ";
- ast_dump_context->dump_expression(this->val_);
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a send statement.
-
-Send_statement*
-Statement::make_send_statement(Expression* channel, Expression* val,
- Location location)
-{
- return new Send_statement(channel, val, location);
-}
-
-// Class Select_clauses::Select_clause.
-
-// Traversal.
-
-int
-Select_clauses::Select_clause::traverse(Traverse* traverse)
-{
- if (!this->is_lowered_
- && (traverse->traverse_mask()
- & (Traverse::traverse_types | Traverse::traverse_expressions)) != 0)
- {
- if (this->channel_ != NULL)
- {
- if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- if (this->val_ != NULL)
- {
- if (Expression::traverse(&this->val_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- if (this->closed_ != NULL)
- {
- if (Expression::traverse(&this->closed_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- if (this->statements_ != NULL)
- {
- if (this->statements_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Lowering. We call a function to register this clause, and arrange
-// to set any variables in any receive clause.
-
-void
-Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
- Block* b, Temporary_statement* sel)
-{
- Location loc = this->location_;
-
- Expression* selref = Expression::make_temporary_reference(sel, loc);
-
- mpz_t ival;
- mpz_init_set_ui(ival, this->index_);
- Expression* index_expr = Expression::make_integer(&ival, NULL, loc);
- mpz_clear(ival);
-
- if (this->is_default_)
- {
- go_assert(this->channel_ == NULL && this->val_ == NULL);
- this->lower_default(b, selref, index_expr);
- this->is_lowered_ = true;
- return;
- }
-
- // Evaluate the channel before the select statement.
- Temporary_statement* channel_temp = Statement::make_temporary(NULL,
- this->channel_,
- loc);
- b->add_statement(channel_temp);
- Expression* chanref = Expression::make_temporary_reference(channel_temp,
- loc);
-
- if (this->is_send_)
- this->lower_send(b, selref, chanref, index_expr);
- else
- this->lower_recv(gogo, function, b, selref, chanref, index_expr);
-
- // Now all references should be handled through the statements, not
- // through here.
- this->is_lowered_ = true;
- this->val_ = NULL;
- this->var_ = NULL;
-}
-
-// Lower a default clause in a select statement.
-
-void
-Select_clauses::Select_clause::lower_default(Block* b, Expression* selref,
- Expression* index_expr)
-{
- Location loc = this->location_;
- Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref,
- index_expr);
- b->add_statement(Statement::make_statement(call, true));
-}
-
-// Lower a send clause in a select statement.
-
-void
-Select_clauses::Select_clause::lower_send(Block* b, Expression* selref,
- Expression* chanref,
- Expression* index_expr)
-{
- Location loc = this->location_;
-
- Channel_type* ct = this->channel_->type()->channel_type();
- if (ct == NULL)
- return;
-
- Type* valtype = ct->element_type();
-
- // Note that copying the value to a temporary here means that we
- // evaluate the send values in the required order.
- Temporary_statement* val = Statement::make_temporary(valtype, this->val_,
- loc);
- b->add_statement(val);
-
- Expression* valref = Expression::make_temporary_reference(val, loc);
- Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
-
- Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref,
- chanref, valaddr, index_expr);
- b->add_statement(Statement::make_statement(call, true));
-}
-
-// Lower a receive clause in a select statement.
-
-void
-Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
- Block* b, Expression* selref,
- Expression* chanref,
- Expression* index_expr)
-{
- Location loc = this->location_;
-
- Channel_type* ct = this->channel_->type()->channel_type();
- if (ct == NULL)
- return;
-
- Type* valtype = ct->element_type();
- Temporary_statement* val = Statement::make_temporary(valtype, NULL, loc);
- b->add_statement(val);
-
- Expression* valref = Expression::make_temporary_reference(val, loc);
- Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
-
- Temporary_statement* closed_temp = NULL;
-
- Expression* call;
- if (this->closed_ == NULL && this->closedvar_ == NULL)
- call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref,
- valaddr, index_expr);
- else
- {
- closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL,
- loc);
- b->add_statement(closed_temp);
- Expression* cref = Expression::make_temporary_reference(closed_temp,
- loc);
- Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc);
- call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref,
- valaddr, caddr, index_expr);
- }
-
- b->add_statement(Statement::make_statement(call, true));
-
- // If the block of statements is executed, arrange for the received
- // value to move from VAL to the place where the statements expect
- // it.
-
- Block* init = NULL;
-
- if (this->var_ != NULL)
- {
- go_assert(this->val_ == NULL);
- valref = Expression::make_temporary_reference(val, loc);
- this->var_->var_value()->set_init(valref);
- this->var_->var_value()->clear_type_from_chan_element();
- }
- else if (this->val_ != NULL && !this->val_->is_sink_expression())
- {
- init = new Block(b, loc);
- valref = Expression::make_temporary_reference(val, loc);
- init->add_statement(Statement::make_assignment(this->val_, valref, loc));
- }
-
- if (this->closedvar_ != NULL)
- {
- go_assert(this->closed_ == NULL);
- Expression* cref = Expression::make_temporary_reference(closed_temp,
- loc);
- this->closedvar_->var_value()->set_init(cref);
- }
- else if (this->closed_ != NULL && !this->closed_->is_sink_expression())
- {
- if (init == NULL)
- init = new Block(b, loc);
- Expression* cref = Expression::make_temporary_reference(closed_temp,
- loc);
- init->add_statement(Statement::make_assignment(this->closed_, cref,
- loc));
- }
-
- if (init != NULL)
- {
- gogo->lower_block(function, init);
-
- if (this->statements_ != NULL)
- init->add_statement(Statement::make_block_statement(this->statements_,
- loc));
- this->statements_ = init;
- }
-}
-
-// Determine types.
-
-void
-Select_clauses::Select_clause::determine_types()
-{
- go_assert(this->is_lowered_);
- if (this->statements_ != NULL)
- this->statements_->determine_types();
-}
-
-// Check types.
-
-void
-Select_clauses::Select_clause::check_types()
-{
- if (this->is_default_)
- return;
-
- Channel_type* ct = this->channel_->type()->channel_type();
- if (ct == NULL)
- {
- error_at(this->channel_->location(), "expected channel");
- return;
- }
-
- if (this->is_send_ && !ct->may_send())
- error_at(this->location(), "invalid send on receive-only channel");
- else if (!this->is_send_ && !ct->may_receive())
- error_at(this->location(), "invalid receive on send-only channel");
-}
-
-// Whether this clause may fall through to the statement which follows
-// the overall select statement.
-
-bool
-Select_clauses::Select_clause::may_fall_through() const
-{
- if (this->statements_ == NULL)
- return true;
- return this->statements_->may_fall_through();
-}
-
-// Return the backend representation for the statements to execute.
-
-Bstatement*
-Select_clauses::Select_clause::get_statements_backend(
- Translate_context* context)
-{
- if (this->statements_ == NULL)
- return NULL;
- Bblock* bblock = this->statements_->get_backend(context);
- return context->backend()->block_statement(bblock);
-}
-
-// Dump the AST representation for a select case clause
-
-void
-Select_clauses::Select_clause::dump_clause(
- Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- if (this->is_default_)
- {
- ast_dump_context->ostream() << "default:";
- }
- else
- {
- ast_dump_context->ostream() << "case " ;
- if (this->is_send_)
- {
- ast_dump_context->dump_expression(this->channel_);
- ast_dump_context->ostream() << " <- " ;
- if (this->val_ != NULL)
- ast_dump_context->dump_expression(this->val_);
- }
- else
- {
- if (this->val_ != NULL)
- ast_dump_context->dump_expression(this->val_);
- if (this->closed_ != NULL)
- {
- // FIXME: can val_ == NULL and closed_ ! = NULL?
- ast_dump_context->ostream() << " , " ;
- ast_dump_context->dump_expression(this->closed_);
- }
- if (this->closedvar_ != NULL || this->var_ != NULL)
- ast_dump_context->ostream() << " := " ;
-
- ast_dump_context->ostream() << " <- " ;
- ast_dump_context->dump_expression(this->channel_);
- }
- ast_dump_context->ostream() << ":" ;
- }
- ast_dump_context->dump_block(this->statements_);
-}
-
-// Class Select_clauses.
-
-// Traversal.
-
-int
-Select_clauses::traverse(Traverse* traverse)
-{
- for (Clauses::iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- {
- if (p->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Lowering. Here we pull out the channel and the send values, to
-// enforce the order of evaluation. We also add explicit send and
-// receive statements to the clauses.
-
-void
-Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b,
- Temporary_statement* sel)
-{
- for (Clauses::iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- p->lower(gogo, function, b, sel);
-}
-
-// Determine types.
-
-void
-Select_clauses::determine_types()
-{
- for (Clauses::iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- p->determine_types();
-}
-
-// Check types.
-
-void
-Select_clauses::check_types()
-{
- for (Clauses::iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- p->check_types();
-}
-
-// Return whether these select clauses fall through to the statement
-// following the overall select statement.
-
-bool
-Select_clauses::may_fall_through() const
-{
- for (Clauses::const_iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- if (p->may_fall_through())
- return true;
- return false;
-}
-
-// Convert to the backend representation. We have already accumulated
-// all the select information. Now we call selectgo, which will
-// return the index of the clause to execute.
-
-Bstatement*
-Select_clauses::get_backend(Translate_context* context,
- Temporary_statement* sel,
- Unnamed_label *break_label,
- Location location)
-{
- size_t count = this->clauses_.size();
- std::vector<std::vector<Bexpression*> > cases(count);
- std::vector<Bstatement*> clauses(count);
-
- Type* int32_type = Type::lookup_integer_type("int32");
-
- int i = 0;
- for (Clauses::iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p, ++i)
- {
- int index = p->index();
- mpz_t ival;
- mpz_init_set_ui(ival, index);
- Expression* index_expr = Expression::make_integer(&ival, int32_type,
- location);
- mpz_clear(ival);
- cases[i].push_back(tree_to_expr(index_expr->get_tree(context)));
-
- Bstatement* s = p->get_statements_backend(context);
- Location gloc = (p->statements() == NULL
- ? p->location()
- : p->statements()->end_location());
- Bstatement* g = break_label->get_goto(context, gloc);
-
- if (s == NULL)
- clauses[i] = g;
- else
- clauses[i] = context->backend()->compound_statement(s, g);
- }
-
- Expression* selref = Expression::make_temporary_reference(sel, location);
- Expression* call = Runtime::make_call(Runtime::SELECTGO, location, 1,
- selref);
- context->gogo()->lower_expression(context->function(), NULL, &call);
- Bexpression* bcall = tree_to_expr(call->get_tree(context));
-
- if (count == 0)
- return context->backend()->expression_statement(bcall);
-
- std::vector<Bstatement*> statements;
- statements.reserve(2);
-
- Bstatement* switch_stmt = context->backend()->switch_statement(bcall,
- cases,
- clauses,
- location);
- statements.push_back(switch_stmt);
-
- Bstatement* ldef = break_label->get_definition(context);
- statements.push_back(ldef);
-
- return context->backend()->statement_list(statements);
-}
-// Dump the AST representation for select clauses.
-
-void
-Select_clauses::dump_clauses(Ast_dump_context* ast_dump_context) const
-{
- for (Clauses::const_iterator p = this->clauses_.begin();
- p != this->clauses_.end();
- ++p)
- p->dump_clause(ast_dump_context);
-}
-
-// Class Select_statement.
-
-// Return the break label for this switch statement, creating it if
-// necessary.
-
-Unnamed_label*
-Select_statement::break_label()
-{
- if (this->break_label_ == NULL)
- this->break_label_ = new Unnamed_label(this->location());
- return this->break_label_;
-}
-
-// Lower a select statement. This will still return a select
-// statement, but it will be modified to implement the order of
-// evaluation rules, and to include the send and receive statements as
-// explicit statements in the clauses.
-
-Statement*
-Select_statement::do_lower(Gogo* gogo, Named_object* function,
- Block* enclosing, Statement_inserter*)
-{
- if (this->is_lowered_)
- return this;
-
- Location loc = this->location();
-
- Block* b = new Block(enclosing, loc);
-
- go_assert(this->sel_ == NULL);
-
- mpz_t ival;
- mpz_init_set_ui(ival, this->clauses_->size());
- Expression* size_expr = Expression::make_integer(&ival, NULL, loc);
- mpz_clear(ival);
-
- Expression* call = Runtime::make_call(Runtime::NEWSELECT, loc, 1, size_expr);
-
- this->sel_ = Statement::make_temporary(NULL, call, loc);
- b->add_statement(this->sel_);
-
- this->clauses_->lower(gogo, function, b, this->sel_);
- this->is_lowered_ = true;
- b->add_statement(this);
-
- return Statement::make_block_statement(b, loc);
-}
-
-// Return the backend representation for a select statement.
-
-Bstatement*
-Select_statement::do_get_backend(Translate_context* context)
-{
- return this->clauses_->get_backend(context, this->sel_, this->break_label(),
- this->location());
-}
-
-// Dump the AST representation for a select statement.
-
-void
-Select_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "select";
- if (ast_dump_context->dump_subblocks())
- {
- ast_dump_context->ostream() << " {" << std::endl;
- this->clauses_->dump_clauses(ast_dump_context);
- ast_dump_context->ostream() << "}";
- }
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a select statement.
-
-Select_statement*
-Statement::make_select_statement(Location location)
-{
- return new Select_statement(location);
-}
-
-// Class For_statement.
-
-// Traversal.
-
-int
-For_statement::do_traverse(Traverse* traverse)
-{
- if (this->init_ != NULL)
- {
- if (this->init_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- if (this->cond_ != NULL)
- {
- if (this->traverse_expression(traverse, &this->cond_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- if (this->post_ != NULL)
- {
- if (this->post_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return this->statements_->traverse(traverse);
-}
-
-// Lower a For_statement into if statements and gotos. Getting rid of
-// complex statements make it easier to handle garbage collection.
-
-Statement*
-For_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
- Statement_inserter*)
-{
- Statement* s;
- Location loc = this->location();
-
- Block* b = new Block(enclosing, this->location());
- if (this->init_ != NULL)
- {
- s = Statement::make_block_statement(this->init_,
- this->init_->start_location());
- b->add_statement(s);
- }
-
- Unnamed_label* entry = NULL;
- if (this->cond_ != NULL)
- {
- entry = new Unnamed_label(this->location());
- b->add_statement(Statement::make_goto_unnamed_statement(entry, loc));
- }
-
- Unnamed_label* top = new Unnamed_label(this->location());
- b->add_statement(Statement::make_unnamed_label_statement(top));
-
- s = Statement::make_block_statement(this->statements_,
- this->statements_->start_location());
- b->add_statement(s);
-
- Location end_loc = this->statements_->end_location();
-
- Unnamed_label* cont = this->continue_label_;
- if (cont != NULL)
- b->add_statement(Statement::make_unnamed_label_statement(cont));
-
- if (this->post_ != NULL)
- {
- s = Statement::make_block_statement(this->post_,
- this->post_->start_location());
- b->add_statement(s);
- end_loc = this->post_->end_location();
- }
-
- if (this->cond_ == NULL)
- b->add_statement(Statement::make_goto_unnamed_statement(top, end_loc));
- else
- {
- b->add_statement(Statement::make_unnamed_label_statement(entry));
-
- Location cond_loc = this->cond_->location();
- Block* then_block = new Block(b, cond_loc);
- s = Statement::make_goto_unnamed_statement(top, cond_loc);
- then_block->add_statement(s);
-
- s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc);
- b->add_statement(s);
- }
-
- Unnamed_label* brk = this->break_label_;
- if (brk != NULL)
- b->add_statement(Statement::make_unnamed_label_statement(brk));
-
- b->set_end_location(end_loc);
-
- return Statement::make_block_statement(b, loc);
-}
-
-// Return the break label, creating it if necessary.
-
-Unnamed_label*
-For_statement::break_label()
-{
- if (this->break_label_ == NULL)
- this->break_label_ = new Unnamed_label(this->location());
- return this->break_label_;
-}
-
-// Return the continue LABEL_EXPR.
-
-Unnamed_label*
-For_statement::continue_label()
-{
- if (this->continue_label_ == NULL)
- this->continue_label_ = new Unnamed_label(this->location());
- return this->continue_label_;
-}
-
-// Set the break and continue labels a for statement. This is used
-// when lowering a for range statement.
-
-void
-For_statement::set_break_continue_labels(Unnamed_label* break_label,
- Unnamed_label* continue_label)
-{
- go_assert(this->break_label_ == NULL && this->continue_label_ == NULL);
- this->break_label_ = break_label;
- this->continue_label_ = continue_label;
-}
-
-// Dump the AST representation for a for statement.
-
-void
-For_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
- if (this->init_ != NULL && ast_dump_context->dump_subblocks())
- {
- ast_dump_context->print_indent();
- ast_dump_context->indent();
- ast_dump_context->ostream() << "// INIT " << std::endl;
- ast_dump_context->dump_block(this->init_);
- ast_dump_context->unindent();
- }
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "for ";
- if (this->cond_ != NULL)
- ast_dump_context->dump_expression(this->cond_);
-
- if (ast_dump_context->dump_subblocks())
- {
- ast_dump_context->ostream() << " {" << std::endl;
- ast_dump_context->dump_block(this->statements_);
- if (this->init_ != NULL)
- {
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "// POST " << std::endl;
- ast_dump_context->dump_block(this->post_);
- }
- ast_dump_context->unindent();
-
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "}";
- }
-
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a for statement.
-
-For_statement*
-Statement::make_for_statement(Block* init, Expression* cond, Block* post,
- Location location)
-{
- return new For_statement(init, cond, post, location);
-}
-
-// Class For_range_statement.
-
-// Traversal.
-
-int
-For_range_statement::do_traverse(Traverse* traverse)
-{
- if (this->traverse_expression(traverse, &this->index_var_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (this->value_var_ != NULL)
- {
- if (this->traverse_expression(traverse, &this->value_var_)
- == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- if (this->traverse_expression(traverse, &this->range_) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return this->statements_->traverse(traverse);
-}
-
-// Lower a for range statement. For simplicity we lower this into a
-// for statement, which will then be lowered in turn to goto
-// statements.
-
-Statement*
-For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
- Statement_inserter*)
-{
- Type* range_type = this->range_->type();
- if (range_type->points_to() != NULL
- && range_type->points_to()->array_type() != NULL
- && !range_type->points_to()->is_slice_type())
- range_type = range_type->points_to();
-
- Type* index_type;
- Type* value_type = NULL;
- if (range_type->array_type() != NULL)
- {
- index_type = Type::lookup_integer_type("int");
- value_type = range_type->array_type()->element_type();
- }
- else if (range_type->is_string_type())
- {
- index_type = Type::lookup_integer_type("int");
- value_type = Type::lookup_integer_type("int32");
- }
- else if (range_type->map_type() != NULL)
- {
- index_type = range_type->map_type()->key_type();
- value_type = range_type->map_type()->val_type();
- }
- else if (range_type->channel_type() != NULL)
- {
- index_type = range_type->channel_type()->element_type();
- if (this->value_var_ != NULL)
- {
- if (!this->value_var_->type()->is_error())
- this->report_error(_("too many variables for range clause "
- "with channel"));
- return Statement::make_error_statement(this->location());
- }
- }
- else
- {
- this->report_error(_("range clause must have "
- "array, slice, string, map, or channel type"));
- return Statement::make_error_statement(this->location());
- }
-
- Location loc = this->location();
- Block* temp_block = new Block(enclosing, loc);
-
- Named_object* range_object = NULL;
- Temporary_statement* range_temp = NULL;
- Var_expression* ve = this->range_->var_expression();
- if (ve != NULL)
- range_object = ve->named_object();
- else
- {
- range_temp = Statement::make_temporary(NULL, this->range_, loc);
- temp_block->add_statement(range_temp);
- this->range_ = NULL;
- }
-
- Temporary_statement* index_temp = Statement::make_temporary(index_type,
- NULL, loc);
- temp_block->add_statement(index_temp);
-
- Temporary_statement* value_temp = NULL;
- if (this->value_var_ != NULL)
- {
- value_temp = Statement::make_temporary(value_type, NULL, loc);
- temp_block->add_statement(value_temp);
- }
-
- Block* body = new Block(temp_block, loc);
-
- Block* init;
- Expression* cond;
- Block* iter_init;
- Block* post;
-
- // Arrange to do a loop appropriate for the type. We will produce
- // for INIT ; COND ; POST {
- // ITER_INIT
- // INDEX = INDEX_TEMP
- // VALUE = VALUE_TEMP // If there is a value
- // original statements
- // }
-
- if (range_type->is_slice_type())
- this->lower_range_slice(gogo, temp_block, body, range_object, range_temp,
- index_temp, value_temp, &init, &cond, &iter_init,
- &post);
- else if (range_type->array_type() != NULL)
- this->lower_range_array(gogo, temp_block, body, range_object, range_temp,
- index_temp, value_temp, &init, &cond, &iter_init,
- &post);
- else if (range_type->is_string_type())
- this->lower_range_string(gogo, temp_block, body, range_object, range_temp,
- index_temp, value_temp, &init, &cond, &iter_init,
- &post);
- else if (range_type->map_type() != NULL)
- this->lower_range_map(gogo, temp_block, body, range_object, range_temp,
- index_temp, value_temp, &init, &cond, &iter_init,
- &post);
- else if (range_type->channel_type() != NULL)
- this->lower_range_channel(gogo, temp_block, body, range_object, range_temp,
- index_temp, value_temp, &init, &cond, &iter_init,
- &post);
- else
- go_unreachable();
-
- if (iter_init != NULL)
- body->add_statement(Statement::make_block_statement(iter_init, loc));
-
- Statement* assign;
- Expression* index_ref = Expression::make_temporary_reference(index_temp, loc);
- if (this->value_var_ == NULL)
- {
- assign = Statement::make_assignment(this->index_var_, index_ref, loc);
- }
- else
- {
- Expression_list* lhs = new Expression_list();
- lhs->push_back(this->index_var_);
- lhs->push_back(this->value_var_);
-
- Expression_list* rhs = new Expression_list();
- rhs->push_back(index_ref);
- rhs->push_back(Expression::make_temporary_reference(value_temp, loc));
-
- assign = Statement::make_tuple_assignment(lhs, rhs, loc);
- }
- body->add_statement(assign);
-
- body->add_statement(Statement::make_block_statement(this->statements_, loc));
-
- body->set_end_location(this->statements_->end_location());
-
- For_statement* loop = Statement::make_for_statement(init, cond, post,
- this->location());
- loop->add_statements(body);
- loop->set_break_continue_labels(this->break_label_, this->continue_label_);
-
- temp_block->add_statement(loop);
-
- return Statement::make_block_statement(temp_block, loc);
-}
-
-// Return a reference to the range, which may be in RANGE_OBJECT or in
-// RANGE_TEMP.
-
-Expression*
-For_range_statement::make_range_ref(Named_object* range_object,
- Temporary_statement* range_temp,
- Location loc)
-{
- if (range_object != NULL)
- return Expression::make_var_reference(range_object, loc);
- else
- return Expression::make_temporary_reference(range_temp, loc);
-}
-
-// Return a call to the predeclared function FUNCNAME passing a
-// reference to the temporary variable ARG.
-
-Expression*
-For_range_statement::call_builtin(Gogo* gogo, const char* funcname,
- Expression* arg,
- Location loc)
-{
- Named_object* no = gogo->lookup_global(funcname);
- go_assert(no != NULL && no->is_function_declaration());
- Expression* func = Expression::make_func_reference(no, NULL, loc);
- Expression_list* params = new Expression_list();
- params->push_back(arg);
- return Expression::make_call(func, params, false, loc);
-}
-
-// Lower a for range over an array.
-
-void
-For_range_statement::lower_range_array(Gogo* gogo,
- Block* enclosing,
- Block* body_block,
- Named_object* range_object,
- Temporary_statement* range_temp,
- Temporary_statement* index_temp,
- Temporary_statement* value_temp,
- Block** pinit,
- Expression** pcond,
- Block** piter_init,
- Block** ppost)
-{
- Location loc = this->location();
-
- // The loop we generate:
- // len_temp := len(range)
- // for index_temp = 0; index_temp < len_temp; index_temp++ {
- // value_temp = range[index_temp]
- // index = index_temp
- // value = value_temp
- // original body
- // }
-
- // Set *PINIT to
- // var len_temp int
- // len_temp = len(range)
- // index_temp = 0
-
- Block* init = new Block(enclosing, loc);
-
- Expression* ref = this->make_range_ref(range_object, range_temp, loc);
- Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
- Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
- len_call, loc);
- init->add_statement(len_temp);
-
- mpz_t zval;
- mpz_init_set_ui(zval, 0UL);
- Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
- mpz_clear(zval);
-
- Temporary_reference_expression* tref =
- Expression::make_temporary_reference(index_temp, loc);
- tref->set_is_lvalue();
- Statement* s = Statement::make_assignment(tref, zexpr, loc);
- init->add_statement(s);
-
- *pinit = init;
-
- // Set *PCOND to
- // index_temp < len_temp
-
- ref = Expression::make_temporary_reference(index_temp, loc);
- Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
- Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
-
- *pcond = lt;
-
- // Set *PITER_INIT to
- // value_temp = range[index_temp]
-
- Block* iter_init = NULL;
- if (value_temp != NULL)
- {
- iter_init = new Block(body_block, loc);
-
- ref = this->make_range_ref(range_object, range_temp, loc);
- Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
- Expression* index = Expression::make_index(ref, ref2, NULL, loc);
-
- tref = Expression::make_temporary_reference(value_temp, loc);
- tref->set_is_lvalue();
- s = Statement::make_assignment(tref, index, loc);
-
- iter_init->add_statement(s);
- }
- *piter_init = iter_init;
-
- // Set *PPOST to
- // index_temp++
-
- Block* post = new Block(enclosing, loc);
- tref = Expression::make_temporary_reference(index_temp, loc);
- tref->set_is_lvalue();
- s = Statement::make_inc_statement(tref);
- post->add_statement(s);
- *ppost = post;
-}
-
-// Lower a for range over a slice.
-
-void
-For_range_statement::lower_range_slice(Gogo* gogo,
- Block* enclosing,
- Block* body_block,
- Named_object* range_object,
- Temporary_statement* range_temp,
- Temporary_statement* index_temp,
- Temporary_statement* value_temp,
- Block** pinit,
- Expression** pcond,
- Block** piter_init,
- Block** ppost)
-{
- Location loc = this->location();
-
- // The loop we generate:
- // for_temp := range
- // len_temp := len(for_temp)
- // for index_temp = 0; index_temp < len_temp; index_temp++ {
- // value_temp = for_temp[index_temp]
- // index = index_temp
- // value = value_temp
- // original body
- // }
- //
- // Using for_temp means that we don't need to check bounds when
- // fetching range_temp[index_temp].
-
- // Set *PINIT to
- // range_temp := range
- // var len_temp int
- // len_temp = len(range_temp)
- // index_temp = 0
-
- Block* init = new Block(enclosing, loc);
-
- Expression* ref = this->make_range_ref(range_object, range_temp, loc);
- Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc);
- init->add_statement(for_temp);
-
- ref = Expression::make_temporary_reference(for_temp, loc);
- Expression* len_call = this->call_builtin(gogo, "len", ref, loc);
- Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(),
- len_call, loc);
- init->add_statement(len_temp);
-
- mpz_t zval;
- mpz_init_set_ui(zval, 0UL);
- Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
- mpz_clear(zval);
-
- Temporary_reference_expression* tref =
- Expression::make_temporary_reference(index_temp, loc);
- tref->set_is_lvalue();
- Statement* s = Statement::make_assignment(tref, zexpr, loc);
- init->add_statement(s);
-
- *pinit = init;
-
- // Set *PCOND to
- // index_temp < len_temp
-
- ref = Expression::make_temporary_reference(index_temp, loc);
- Expression* ref2 = Expression::make_temporary_reference(len_temp, loc);
- Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc);
-
- *pcond = lt;
-
- // Set *PITER_INIT to
- // value_temp = range[index_temp]
-
- Block* iter_init = NULL;
- if (value_temp != NULL)
- {
- iter_init = new Block(body_block, loc);
-
- ref = Expression::make_temporary_reference(for_temp, loc);
- Expression* ref2 = Expression::make_temporary_reference(index_temp, loc);
- Expression* index = Expression::make_index(ref, ref2, NULL, loc);
-
- tref = Expression::make_temporary_reference(value_temp, loc);
- tref->set_is_lvalue();
- s = Statement::make_assignment(tref, index, loc);
-
- iter_init->add_statement(s);
- }
- *piter_init = iter_init;
-
- // Set *PPOST to
- // index_temp++
-
- Block* post = new Block(enclosing, loc);
- tref = Expression::make_temporary_reference(index_temp, loc);
- tref->set_is_lvalue();
- s = Statement::make_inc_statement(tref);
- post->add_statement(s);
- *ppost = post;
-}
-
-// Lower a for range over a string.
-
-void
-For_range_statement::lower_range_string(Gogo*,
- Block* enclosing,
- Block* body_block,
- Named_object* range_object,
- Temporary_statement* range_temp,
- Temporary_statement* index_temp,
- Temporary_statement* value_temp,
- Block** pinit,
- Expression** pcond,
- Block** piter_init,
- Block** ppost)
-{
- Location loc = this->location();
-
- // The loop we generate:
- // var next_index_temp int
- // for index_temp = 0; ; index_temp = next_index_temp {
- // next_index_temp, value_temp = stringiter2(range, index_temp)
- // if next_index_temp == 0 {
- // break
- // }
- // index = index_temp
- // value = value_temp
- // original body
- // }
-
- // Set *PINIT to
- // var next_index_temp int
- // index_temp = 0
-
- Block* init = new Block(enclosing, loc);
-
- Temporary_statement* next_index_temp =
- Statement::make_temporary(index_temp->type(), NULL, loc);
- init->add_statement(next_index_temp);
-
- mpz_t zval;
- mpz_init_set_ui(zval, 0UL);
- Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
-
- Temporary_reference_expression* ref =
- Expression::make_temporary_reference(index_temp, loc);
- ref->set_is_lvalue();
- Statement* s = Statement::make_assignment(ref, zexpr, loc);
-
- init->add_statement(s);
- *pinit = init;
-
- // The loop has no condition.
-
- *pcond = NULL;
-
- // Set *PITER_INIT to
- // next_index_temp = runtime.stringiter(range, index_temp)
- // or
- // next_index_temp, value_temp = runtime.stringiter2(range, index_temp)
- // followed by
- // if next_index_temp == 0 {
- // break
- // }
-
- Block* iter_init = new Block(body_block, loc);
-
- Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
- Expression* p2 = Expression::make_temporary_reference(index_temp, loc);
- Call_expression* call = Runtime::make_call((value_temp == NULL
- ? Runtime::STRINGITER
- : Runtime::STRINGITER2),
- loc, 2, p1, p2);
-
- if (value_temp == NULL)
- {
- ref = Expression::make_temporary_reference(next_index_temp, loc);
- ref->set_is_lvalue();
- s = Statement::make_assignment(ref, call, loc);
- }
- else
- {
- Expression_list* lhs = new Expression_list();
-
- ref = Expression::make_temporary_reference(next_index_temp, loc);
- ref->set_is_lvalue();
- lhs->push_back(ref);
-
- ref = Expression::make_temporary_reference(value_temp, loc);
- ref->set_is_lvalue();
- lhs->push_back(ref);
-
- Expression_list* rhs = new Expression_list();
- rhs->push_back(Expression::make_call_result(call, 0));
- rhs->push_back(Expression::make_call_result(call, 1));
-
- s = Statement::make_tuple_assignment(lhs, rhs, loc);
- }
- iter_init->add_statement(s);
-
- ref = Expression::make_temporary_reference(next_index_temp, loc);
- zexpr = Expression::make_integer(&zval, NULL, loc);
- mpz_clear(zval);
- Expression* equals = Expression::make_binary(OPERATOR_EQEQ, ref, zexpr, loc);
-
- Block* then_block = new Block(iter_init, loc);
- s = Statement::make_break_statement(this->break_label(), loc);
- then_block->add_statement(s);
-
- s = Statement::make_if_statement(equals, then_block, NULL, loc);
- iter_init->add_statement(s);
-
- *piter_init = iter_init;
-
- // Set *PPOST to
- // index_temp = next_index_temp
-
- Block* post = new Block(enclosing, loc);
-
- Temporary_reference_expression* lhs =
- Expression::make_temporary_reference(index_temp, loc);
- lhs->set_is_lvalue();
- Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc);
- s = Statement::make_assignment(lhs, rhs, loc);
-
- post->add_statement(s);
- *ppost = post;
-}
-
-// Lower a for range over a map.
-
-void
-For_range_statement::lower_range_map(Gogo*,
- Block* enclosing,
- Block* body_block,
- Named_object* range_object,
- Temporary_statement* range_temp,
- Temporary_statement* index_temp,
- Temporary_statement* value_temp,
- Block** pinit,
- Expression** pcond,
- Block** piter_init,
- Block** ppost)
-{
- Location loc = this->location();
-
- // The runtime uses a struct to handle ranges over a map. The
- // struct is four pointers long. The first pointer is NULL when we
- // have completed the iteration.
-
- // The loop we generate:
- // var hiter map_iteration_struct
- // for mapiterinit(range, &hiter); hiter[0] != nil; mapiternext(&hiter) {
- // mapiter2(hiter, &index_temp, &value_temp)
- // index = index_temp
- // value = value_temp
- // original body
- // }
-
- // Set *PINIT to
- // var hiter map_iteration_struct
- // runtime.mapiterinit(range, &hiter)
-
- Block* init = new Block(enclosing, loc);
-
- Type* map_iteration_type = Runtime::map_iteration_type();
- Temporary_statement* hiter = Statement::make_temporary(map_iteration_type,
- NULL, loc);
- init->add_statement(hiter);
-
- Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
- Expression* ref = Expression::make_temporary_reference(hiter, loc);
- Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
- Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 2, p1, p2);
- init->add_statement(Statement::make_statement(call, true));
-
- *pinit = init;
-
- // Set *PCOND to
- // hiter[0] != nil
-
- ref = Expression::make_temporary_reference(hiter, loc);
-
- mpz_t zval;
- mpz_init_set_ui(zval, 0UL);
- Expression* zexpr = Expression::make_integer(&zval, NULL, loc);
- mpz_clear(zval);
-
- Expression* index = Expression::make_index(ref, zexpr, NULL, loc);
-
- Expression* ne = Expression::make_binary(OPERATOR_NOTEQ, index,
- Expression::make_nil(loc),
- loc);
-
- *pcond = ne;
-
- // Set *PITER_INIT to
- // mapiter1(hiter, &index_temp)
- // or
- // mapiter2(hiter, &index_temp, &value_temp)
-
- Block* iter_init = new Block(body_block, loc);
-
- ref = Expression::make_temporary_reference(hiter, loc);
- p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
- ref = Expression::make_temporary_reference(index_temp, loc);
- p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
- if (value_temp == NULL)
- call = Runtime::make_call(Runtime::MAPITER1, loc, 2, p1, p2);
- else
- {
- ref = Expression::make_temporary_reference(value_temp, loc);
- Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
- call = Runtime::make_call(Runtime::MAPITER2, loc, 3, p1, p2, p3);
- }
- iter_init->add_statement(Statement::make_statement(call, true));
-
- *piter_init = iter_init;
-
- // Set *PPOST to
- // mapiternext(&hiter)
-
- Block* post = new Block(enclosing, loc);
-
- ref = Expression::make_temporary_reference(hiter, loc);
- p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
- call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1);
- post->add_statement(Statement::make_statement(call, true));
-
- *ppost = post;
-}
-
-// Lower a for range over a channel.
-
-void
-For_range_statement::lower_range_channel(Gogo*,
- Block*,
- Block* body_block,
- Named_object* range_object,
- Temporary_statement* range_temp,
- Temporary_statement* index_temp,
- Temporary_statement* value_temp,
- Block** pinit,
- Expression** pcond,
- Block** piter_init,
- Block** ppost)
-{
- go_assert(value_temp == NULL);
-
- Location loc = this->location();
-
- // The loop we generate:
- // for {
- // index_temp, ok_temp = <-range
- // if !ok_temp {
- // break
- // }
- // index = index_temp
- // original body
- // }
-
- // We have no initialization code, no condition, and no post code.
-
- *pinit = NULL;
- *pcond = NULL;
- *ppost = NULL;
-
- // Set *PITER_INIT to
- // index_temp, ok_temp = <-range
- // if !ok_temp {
- // break
- // }
-
- Block* iter_init = new Block(body_block, loc);
-
- Temporary_statement* ok_temp =
- Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
- iter_init->add_statement(ok_temp);
-
- Expression* cref = this->make_range_ref(range_object, range_temp, loc);
- Temporary_reference_expression* iref =
- Expression::make_temporary_reference(index_temp, loc);
- iref->set_is_lvalue();
- Temporary_reference_expression* oref =
- Expression::make_temporary_reference(ok_temp, loc);
- oref->set_is_lvalue();
- Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref,
- loc);
- iter_init->add_statement(s);
-
- Block* then_block = new Block(iter_init, loc);
- s = Statement::make_break_statement(this->break_label(), loc);
- then_block->add_statement(s);
-
- oref = Expression::make_temporary_reference(ok_temp, loc);
- Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc);
- s = Statement::make_if_statement(cond, then_block, NULL, loc);
- iter_init->add_statement(s);
-
- *piter_init = iter_init;
-}
-
-// Return the break LABEL_EXPR.
-
-Unnamed_label*
-For_range_statement::break_label()
-{
- if (this->break_label_ == NULL)
- this->break_label_ = new Unnamed_label(this->location());
- return this->break_label_;
-}
-
-// Return the continue LABEL_EXPR.
-
-Unnamed_label*
-For_range_statement::continue_label()
-{
- if (this->continue_label_ == NULL)
- this->continue_label_ = new Unnamed_label(this->location());
- return this->continue_label_;
-}
-
-// Dump the AST representation for a for range statement.
-
-void
-For_range_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const
-{
-
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "for ";
- ast_dump_context->dump_expression(this->index_var_);
- if (this->value_var_ != NULL)
- {
- ast_dump_context->ostream() << ", ";
- ast_dump_context->dump_expression(this->value_var_);
- }
-
- ast_dump_context->ostream() << " = range ";
- ast_dump_context->dump_expression(this->range_);
- if (ast_dump_context->dump_subblocks())
- {
- ast_dump_context->ostream() << " {" << std::endl;
-
- ast_dump_context->indent();
-
- ast_dump_context->dump_block(this->statements_);
-
- ast_dump_context->unindent();
- ast_dump_context->print_indent();
- ast_dump_context->ostream() << "}";
- }
- ast_dump_context->ostream() << std::endl;
-}
-
-// Make a for statement with a range clause.
-
-For_range_statement*
-Statement::make_for_range_statement(Expression* index_var,
- Expression* value_var,
- Expression* range,
- Location location)
-{
- return new For_range_statement(index_var, value_var, range, location);
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/statements.h b/gcc-4.8.1/gcc/go/gofrontend/statements.h
deleted file mode 100644
index c59957107..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/statements.h
+++ /dev/null
@@ -1,1570 +0,0 @@
-// statements.h -- Go frontend statements. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_STATEMENTS_H
-#define GO_STATEMENTS_H
-
-#include "operator.h"
-
-class Gogo;
-class Traverse;
-class Statement_inserter;
-class Block;
-class Function;
-class Unnamed_label;
-class Temporary_statement;
-class Variable_declaration_statement;
-class Return_statement;
-class Thunk_statement;
-class Label_statement;
-class For_statement;
-class For_range_statement;
-class Switch_statement;
-class Type_switch_statement;
-class Send_statement;
-class Select_statement;
-class Variable;
-class Named_object;
-class Label;
-class Translate_context;
-class Expression;
-class Expression_list;
-class Struct_type;
-class Call_expression;
-class Map_index_expression;
-class Receive_expression;
-class Case_clauses;
-class Type_case_clauses;
-class Select_clauses;
-class Typed_identifier_list;
-class Bexpression;
-class Bstatement;
-class Bvariable;
-class Ast_dump_context;
-
-// This class is used to traverse assignments made by a statement
-// which makes assignments.
-
-class Traverse_assignments
-{
- public:
- Traverse_assignments()
- { }
-
- virtual ~Traverse_assignments()
- { }
-
- // This is called for a variable initialization.
- virtual void
- initialize_variable(Named_object*) = 0;
-
- // This is called for each assignment made by the statement. PLHS
- // points to the left hand side, and PRHS points to the right hand
- // side. PRHS may be NULL if there is no associated expression, as
- // in the bool set by a non-blocking receive.
- virtual void
- assignment(Expression** plhs, Expression** prhs) = 0;
-
- // This is called for each expression which is not passed to the
- // assignment function. This is used for some of the statements
- // which assign two values, for which there is no expression which
- // describes the value. For ++ and -- the value is passed to both
- // the assignment method and the rhs method. IS_STORED is true if
- // this value is being stored directly. It is false if the value is
- // computed but not stored. IS_LOCAL is true if the value is being
- // stored in a local variable or this is being called by a return
- // statement.
- virtual void
- value(Expression**, bool is_stored, bool is_local) = 0;
-};
-
-// A single statement.
-
-class Statement
-{
- public:
- // The types of statements.
- enum Statement_classification
- {
- STATEMENT_ERROR,
- STATEMENT_VARIABLE_DECLARATION,
- STATEMENT_TEMPORARY,
- STATEMENT_ASSIGNMENT,
- STATEMENT_EXPRESSION,
- STATEMENT_BLOCK,
- STATEMENT_GO,
- STATEMENT_DEFER,
- STATEMENT_RETURN,
- STATEMENT_BREAK_OR_CONTINUE,
- STATEMENT_GOTO,
- STATEMENT_GOTO_UNNAMED,
- STATEMENT_LABEL,
- STATEMENT_UNNAMED_LABEL,
- STATEMENT_IF,
- STATEMENT_CONSTANT_SWITCH,
- STATEMENT_SEND,
- STATEMENT_SELECT,
-
- // These statements types are created by the parser, but they
- // disappear during the lowering pass.
- STATEMENT_ASSIGNMENT_OPERATION,
- STATEMENT_TUPLE_ASSIGNMENT,
- STATEMENT_TUPLE_MAP_ASSIGNMENT,
- STATEMENT_MAP_ASSIGNMENT,
- STATEMENT_TUPLE_RECEIVE_ASSIGNMENT,
- STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT,
- STATEMENT_INCDEC,
- STATEMENT_FOR,
- STATEMENT_FOR_RANGE,
- STATEMENT_SWITCH,
- STATEMENT_TYPE_SWITCH
- };
-
- Statement(Statement_classification, Location);
-
- virtual ~Statement();
-
- // Make a variable declaration.
- static Statement*
- make_variable_declaration(Named_object*);
-
- // Make a statement which creates a temporary variable and
- // initializes it to an expression. The block is used if the
- // temporary variable has to be explicitly destroyed; the variable
- // must still be added to the block. References to the temporary
- // variable may be constructed using make_temporary_reference.
- // Either the type or the initialization expression may be NULL, but
- // not both.
- static Temporary_statement*
- make_temporary(Type*, Expression*, Location);
-
- // Make an assignment statement.
- static Statement*
- make_assignment(Expression*, Expression*, Location);
-
- // Make an assignment operation (+=, etc.).
- static Statement*
- make_assignment_operation(Operator, Expression*, Expression*,
- Location);
-
- // Make a tuple assignment statement.
- static Statement*
- make_tuple_assignment(Expression_list*, Expression_list*, Location);
-
- // Make an assignment from a map index to a pair of variables.
- static Statement*
- make_tuple_map_assignment(Expression* val, Expression* present,
- Expression*, Location);
-
- // Make a statement which assigns a pair of values to a map.
- static Statement*
- make_map_assignment(Expression*, Expression* val,
- Expression* should_set, Location);
-
- // Make an assignment from a nonblocking receive to a pair of
- // variables.
- static Statement*
- make_tuple_receive_assignment(Expression* val, Expression* closed,
- Expression* channel, Location);
-
- // Make an assignment from a type guard to a pair of variables.
- static Statement*
- make_tuple_type_guard_assignment(Expression* val, Expression* ok,
- Expression* expr, Type* type,
- Location);
-
- // Make an expression statement from an Expression. IS_IGNORED is
- // true if the value is being explicitly ignored, as in an
- // assignment to _.
- static Statement*
- make_statement(Expression*, bool is_ignored);
-
- // Make a block statement from a Block. This is an embedded list of
- // statements which may also include variable definitions.
- static Statement*
- make_block_statement(Block*, Location);
-
- // Make an increment statement.
- static Statement*
- make_inc_statement(Expression*);
-
- // Make a decrement statement.
- static Statement*
- make_dec_statement(Expression*);
-
- // Make a go statement.
- static Statement*
- make_go_statement(Call_expression* call, Location);
-
- // Make a defer statement.
- static Statement*
- make_defer_statement(Call_expression* call, Location);
-
- // Make a return statement.
- static Return_statement*
- make_return_statement(Expression_list*, Location);
-
- // Make a break statement.
- static Statement*
- make_break_statement(Unnamed_label* label, Location);
-
- // Make a continue statement.
- static Statement*
- make_continue_statement(Unnamed_label* label, Location);
-
- // Make a goto statement.
- static Statement*
- make_goto_statement(Label* label, Location);
-
- // Make a goto statement to an unnamed label.
- static Statement*
- make_goto_unnamed_statement(Unnamed_label* label, Location);
-
- // Make a label statement--where the label is defined.
- static Statement*
- make_label_statement(Label* label, Location);
-
- // Make an unnamed label statement--where the label is defined.
- static Statement*
- make_unnamed_label_statement(Unnamed_label* label);
-
- // Make an if statement.
- static Statement*
- make_if_statement(Expression* cond, Block* then_block, Block* else_block,
- Location);
-
- // Make a switch statement.
- static Switch_statement*
- make_switch_statement(Expression* switch_val, Location);
-
- // Make a type switch statement.
- static Type_switch_statement*
- make_type_switch_statement(Named_object* var, Expression*, Location);
-
- // Make a send statement.
- static Send_statement*
- make_send_statement(Expression* channel, Expression* val, Location);
-
- // Make a select statement.
- static Select_statement*
- make_select_statement(Location);
-
- // Make a for statement.
- static For_statement*
- make_for_statement(Block* init, Expression* cond, Block* post,
- Location location);
-
- // Make a for statement with a range clause.
- static For_range_statement*
- make_for_range_statement(Expression* index_var, Expression* value_var,
- Expression* range, Location);
-
- // Return the statement classification.
- Statement_classification
- classification() const
- { return this->classification_; }
-
- // Get the statement location.
- Location
- location() const
- { return this->location_; }
-
- // Traverse the tree.
- int
- traverse(Block*, size_t* index, Traverse*);
-
- // Traverse the contents of this statement--the expressions and
- // statements which it contains.
- int
- traverse_contents(Traverse*);
-
- // If this statement assigns some values, it calls a function for
- // each value to which this statement assigns a value, and returns
- // true. If this statement does not assign any values, it returns
- // false.
- bool
- traverse_assignments(Traverse_assignments* tassign);
-
- // Lower a statement. This is called immediately after parsing to
- // simplify statements for further processing. It returns the same
- // Statement or a new one. FUNCTION is the function containing this
- // statement. BLOCK is the block containing this statement.
- // INSERTER can be used to insert new statements before this one.
- Statement*
- lower(Gogo* gogo, Named_object* function, Block* block,
- Statement_inserter* inserter)
- { return this->do_lower(gogo, function, block, inserter); }
-
- // Set type information for unnamed constants.
- void
- determine_types();
-
- // Check types in a statement. This simply checks that any
- // expressions used by the statement have the right type.
- void
- check_types(Gogo* gogo)
- { this->do_check_types(gogo); }
-
- // Return whether this is a block statement.
- bool
- is_block_statement() const
- { return this->classification_ == STATEMENT_BLOCK; }
-
- // If this is a variable declaration statement, return it.
- // Otherwise return NULL.
- Variable_declaration_statement*
- variable_declaration_statement()
- {
- return this->convert<Variable_declaration_statement,
- STATEMENT_VARIABLE_DECLARATION>();
- }
-
- // If this is a return statement, return it. Otherwise return NULL.
- Return_statement*
- return_statement()
- { return this->convert<Return_statement, STATEMENT_RETURN>(); }
-
- // If this is a thunk statement (a go or defer statement), return
- // it. Otherwise return NULL.
- Thunk_statement*
- thunk_statement();
-
- // If this is a label statement, return it. Otherwise return NULL.
- Label_statement*
- label_statement()
- { return this->convert<Label_statement, STATEMENT_LABEL>(); }
-
- // If this is a for statement, return it. Otherwise return NULL.
- For_statement*
- for_statement()
- { return this->convert<For_statement, STATEMENT_FOR>(); }
-
- // If this is a for statement over a range clause, return it.
- // Otherwise return NULL.
- For_range_statement*
- for_range_statement()
- { return this->convert<For_range_statement, STATEMENT_FOR_RANGE>(); }
-
- // If this is a switch statement, return it. Otherwise return NULL.
- Switch_statement*
- switch_statement()
- { return this->convert<Switch_statement, STATEMENT_SWITCH>(); }
-
- // If this is a type switch statement, return it. Otherwise return
- // NULL.
- Type_switch_statement*
- type_switch_statement()
- { return this->convert<Type_switch_statement, STATEMENT_TYPE_SWITCH>(); }
-
- // If this is a select statement, return it. Otherwise return NULL.
- Select_statement*
- select_statement()
- { return this->convert<Select_statement, STATEMENT_SELECT>(); }
-
- // Return true if this statement may fall through--if after
- // executing this statement we may go on to execute the following
- // statement, if any.
- bool
- may_fall_through() const
- { return this->do_may_fall_through(); }
-
- // Convert the statement to the backend representation.
- Bstatement*
- get_backend(Translate_context*);
-
- // Dump AST representation of a statement to a dump context.
- void
- dump_statement(Ast_dump_context*) const;
-
- protected:
- // Implemented by child class: traverse the tree.
- virtual int
- do_traverse(Traverse*) = 0;
-
- // Implemented by child class: traverse assignments. Any statement
- // which includes an assignment should implement this.
- virtual bool
- do_traverse_assignments(Traverse_assignments*)
- { return false; }
-
- // Implemented by the child class: lower this statement to a simpler
- // one.
- virtual Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
- { return this; }
-
- // Implemented by child class: set type information for unnamed
- // constants. Any statement which includes an expression needs to
- // implement this.
- virtual void
- do_determine_types()
- { }
-
- // Implemented by child class: check types of expressions used in a
- // statement.
- virtual void
- do_check_types(Gogo*)
- { }
-
- // Implemented by child class: return true if this statement may
- // fall through.
- virtual bool
- do_may_fall_through() const
- { return true; }
-
- // Implemented by child class: convert to backend representation.
- virtual Bstatement*
- do_get_backend(Translate_context*) = 0;
-
- // Implemented by child class: dump ast representation.
- virtual void
- do_dump_statement(Ast_dump_context*) const = 0;
-
- // Traverse an expression in a statement.
- int
- traverse_expression(Traverse*, Expression**);
-
- // Traverse an expression list in a statement. The Expression_list
- // may be NULL.
- int
- traverse_expression_list(Traverse*, Expression_list*);
-
- // Traverse a type in a statement.
- int
- traverse_type(Traverse*, Type*);
-
- // For children to call when they detect that they are in error.
- void
- set_is_error();
-
- // For children to call to report an error conveniently.
- void
- report_error(const char*);
-
- // For children to return an error statement from lower().
- static Statement*
- make_error_statement(Location);
-
- private:
- // Convert to the desired statement classification, or return NULL.
- // This is a controlled dynamic cast.
- template<typename Statement_class, Statement_classification sc>
- Statement_class*
- convert()
- {
- return (this->classification_ == sc
- ? static_cast<Statement_class*>(this)
- : NULL);
- }
-
- template<typename Statement_class, Statement_classification sc>
- const Statement_class*
- convert() const
- {
- return (this->classification_ == sc
- ? static_cast<const Statement_class*>(this)
- : NULL);
- }
-
- // The statement classification.
- Statement_classification classification_;
- // The location in the input file of the start of this statement.
- Location location_;
-};
-
-// A statement which creates and initializes a temporary variable.
-
-class Temporary_statement : public Statement
-{
- public:
- Temporary_statement(Type* type, Expression* init, Location location)
- : Statement(STATEMENT_TEMPORARY, location),
- type_(type), init_(init), bvariable_(NULL), are_hidden_fields_ok_(false),
- is_address_taken_(false)
- { }
-
- // Return the type of the temporary variable.
- Type*
- type() const;
-
- // Return the initializer if there is one.
- Expression*
- init() const
- { return this->init_; }
-
- // Note that it is OK for this statement to set hidden fields.
- void
- set_hidden_fields_are_ok()
- { this->are_hidden_fields_ok_ = true; }
-
- // Record that something takes the address of this temporary
- // variable.
- void
- set_is_address_taken()
- { this->is_address_taken_ = true; }
-
- // Return the temporary variable. This should not be called until
- // after the statement itself has been converted.
- Bvariable*
- get_backend_variable(Translate_context*) const;
-
- protected:
- int
- do_traverse(Traverse*);
-
- bool
- do_traverse_assignments(Traverse_assignments*);
-
- void
- do_determine_types();
-
- void
- do_check_types(Gogo*);
-
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The type of the temporary variable.
- Type* type_;
- // The initial value of the temporary variable. This may be NULL.
- Expression* init_;
- // The backend representation of the temporary variable.
- Bvariable* bvariable_;
- // True if this statement may set hidden fields when assigning the
- // value to the temporary. This is used for generated method stubs.
- bool are_hidden_fields_ok_;
- // True if something takes the address of this temporary variable.
- bool is_address_taken_;
-};
-
-// A variable declaration. This marks the point in the code where a
-// variable is declared. The Variable is also attached to a Block.
-
-class Variable_declaration_statement : public Statement
-{
- public:
- Variable_declaration_statement(Named_object* var);
-
- // The variable being declared.
- Named_object*
- var()
- { return this->var_; }
-
- protected:
- int
- do_traverse(Traverse*);
-
- bool
- do_traverse_assignments(Traverse_assignments*);
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- Named_object* var_;
-};
-
-// A return statement.
-
-class Return_statement : public Statement
-{
- public:
- Return_statement(Expression_list* vals, Location location)
- : Statement(STATEMENT_RETURN, location),
- vals_(vals), are_hidden_fields_ok_(false), is_lowered_(false)
- { }
-
- // The list of values being returned. This may be NULL.
- const Expression_list*
- vals() const
- { return this->vals_; }
-
- // Note that it is OK for this return statement to set hidden
- // fields.
- void
- set_hidden_fields_are_ok()
- { this->are_hidden_fields_ok_ = true; }
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return this->traverse_expression_list(traverse, this->vals_); }
-
- bool
- do_traverse_assignments(Traverse_assignments*);
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- bool
- do_may_fall_through() const
- { return false; }
-
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // Return values. This may be NULL.
- Expression_list* vals_;
- // True if this statement may pass hidden fields in the return
- // value. This is used for generated method stubs.
- bool are_hidden_fields_ok_;
- // True if this statement has been lowered.
- bool is_lowered_;
-};
-
-// A send statement.
-
-class Send_statement : public Statement
-{
- public:
- Send_statement(Expression* channel, Expression* val,
- Location location)
- : Statement(STATEMENT_SEND, location),
- channel_(channel), val_(val)
- { }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- void
- do_determine_types();
-
- void
- do_check_types(Gogo*);
-
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The channel on which to send the value.
- Expression* channel_;
- // The value to send.
- Expression* val_;
-};
-
-// Select_clauses holds the clauses of a select statement. This is
-// built by the parser.
-
-class Select_clauses
-{
- public:
- Select_clauses()
- : clauses_()
- { }
-
- // Add a new clause. IS_SEND is true if this is a send clause,
- // false for a receive clause. For a send clause CHANNEL is the
- // channel and VAL is the value to send. For a receive clause
- // CHANNEL is the channel, VAL is either NULL or a Var_expression
- // for the variable to set, and CLOSED is either NULL or a
- // Var_expression to set to whether the channel is closed. If VAL
- // is NULL, VAR may be a variable to be initialized with the
- // received value, and CLOSEDVAR ma be a variable to be initialized
- // with whether the channel is closed. IS_DEFAULT is true if this
- // is the default clause. STATEMENTS is the list of statements to
- // execute.
- void
- add(bool is_send, Expression* channel, Expression* val, Expression* closed,
- Named_object* var, Named_object* closedvar, bool is_default,
- Block* statements, Location location)
- {
- int index = static_cast<int>(this->clauses_.size());
- this->clauses_.push_back(Select_clause(index, is_send, channel, val,
- closed, var, closedvar, is_default,
- statements, location));
- }
-
- size_t
- size() const
- { return this->clauses_.size(); }
-
- // Traverse the select clauses.
- int
- traverse(Traverse*);
-
- // Lower statements.
- void
- lower(Gogo*, Named_object*, Block*, Temporary_statement*);
-
- // Determine types.
- void
- determine_types();
-
- // Check types.
- void
- check_types();
-
- // Whether the select clauses may fall through to the statement
- // which follows the overall select statement.
- bool
- may_fall_through() const;
-
- // Convert to the backend representation.
- Bstatement*
- get_backend(Translate_context*, Temporary_statement* sel,
- Unnamed_label* break_label, Location);
-
- // Dump AST representation.
- void
- dump_clauses(Ast_dump_context*) const;
-
- private:
- // A single clause.
- class Select_clause
- {
- public:
- Select_clause()
- : channel_(NULL), val_(NULL), closed_(NULL), var_(NULL),
- closedvar_(NULL), statements_(NULL), is_send_(false),
- is_default_(false)
- { }
-
- Select_clause(int index, bool is_send, Expression* channel,
- Expression* val, Expression* closed, Named_object* var,
- Named_object* closedvar, bool is_default, Block* statements,
- Location location)
- : index_(index), channel_(channel), val_(val), closed_(closed),
- var_(var), closedvar_(closedvar), statements_(statements),
- location_(location), is_send_(is_send), is_default_(is_default),
- is_lowered_(false)
- { go_assert(is_default ? channel == NULL : channel != NULL); }
-
- // Return the index of this clause.
- int
- index() const
- { return this->index_; }
-
- // Traverse the select clause.
- int
- traverse(Traverse*);
-
- // Lower statements.
- void
- lower(Gogo*, Named_object*, Block*, Temporary_statement*);
-
- // Determine types.
- void
- determine_types();
-
- // Check types.
- void
- check_types();
-
- // Return true if this is the default clause.
- bool
- is_default() const
- { return this->is_default_; }
-
- // Return the channel. This will return NULL for the default
- // clause.
- Expression*
- channel() const
- { return this->channel_; }
-
- // Return true for a send, false for a receive.
- bool
- is_send() const
- {
- go_assert(!this->is_default_);
- return this->is_send_;
- }
-
- // Return the statements.
- const Block*
- statements() const
- { return this->statements_; }
-
- // Return the location.
- Location
- location() const
- { return this->location_; }
-
- // Whether this clause may fall through to the statement which
- // follows the overall select statement.
- bool
- may_fall_through() const;
-
- // Convert the statements to the backend representation.
- Bstatement*
- get_statements_backend(Translate_context*);
-
- // Dump AST representation.
- void
- dump_clause(Ast_dump_context*) const;
-
- private:
- void
- lower_default(Block*, Expression*, Expression*);
-
- void
- lower_send(Block*, Expression*, Expression*, Expression*);
-
- void
- lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*,
- Expression*);
-
- // The index of this case in the generated switch statement.
- int index_;
- // The channel.
- Expression* channel_;
- // The value to send or the lvalue to receive into.
- Expression* val_;
- // The lvalue to set to whether the channel is closed on a
- // receive.
- Expression* closed_;
- // The variable to initialize, for "case a := <-ch".
- Named_object* var_;
- // The variable to initialize to whether the channel is closed,
- // for "case a, c := <-ch".
- Named_object* closedvar_;
- // The statements to execute.
- Block* statements_;
- // The location of this clause.
- Location location_;
- // Whether this is a send or a receive.
- bool is_send_;
- // Whether this is the default.
- bool is_default_;
- // Whether this has been lowered.
- bool is_lowered_;
- };
-
- typedef std::vector<Select_clause> Clauses;
-
- Clauses clauses_;
-};
-
-// A select statement.
-
-class Select_statement : public Statement
-{
- public:
- Select_statement(Location location)
- : Statement(STATEMENT_SELECT, location),
- clauses_(NULL), sel_(NULL), break_label_(NULL), is_lowered_(false)
- { }
-
- // Add the clauses.
- void
- add_clauses(Select_clauses* clauses)
- {
- go_assert(this->clauses_ == NULL);
- this->clauses_ = clauses;
- }
-
- // Return the break label for this select statement.
- Unnamed_label*
- break_label();
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return this->clauses_->traverse(traverse); }
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- void
- do_determine_types()
- { this->clauses_->determine_types(); }
-
- void
- do_check_types(Gogo*)
- { this->clauses_->check_types(); }
-
- bool
- do_may_fall_through() const
- { return this->clauses_->may_fall_through(); }
-
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The select clauses.
- Select_clauses* clauses_;
- // A temporary which holds the select structure we build up at runtime.
- Temporary_statement* sel_;
- // The break label.
- Unnamed_label* break_label_;
- // Whether this statement has been lowered.
- bool is_lowered_;
-};
-
-// A statement which requires a thunk: go or defer.
-
-class Thunk_statement : public Statement
-{
- public:
- Thunk_statement(Statement_classification, Call_expression*,
- Location);
-
- // Return the call expression.
- Expression*
- call() const
- { return this->call_; }
-
- // Simplify a go or defer statement so that it only uses a single
- // parameter.
- bool
- simplify_statement(Gogo*, Named_object*, Block*);
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- bool
- do_traverse_assignments(Traverse_assignments*);
-
- void
- do_determine_types();
-
- void
- do_check_types(Gogo*);
-
- // Return the function and argument for the call.
- bool
- get_fn_and_arg(Expression** pfn, Expression** parg);
-
- private:
- // Return whether this is a simple go statement.
- bool
- is_simple(Function_type*) const;
-
- // Return whether the thunk function is a constant.
- bool
- is_constant_function() const;
-
- // Build the struct to use for a complex case.
- Struct_type*
- build_struct(Function_type* fntype);
-
- // Build the thunk.
- void
- build_thunk(Gogo*, const std::string&);
-
- // Set the name to use for thunk field N.
- void
- thunk_field_param(int n, char* buf, size_t buflen);
-
- // The function call to be executed in a separate thread (go) or
- // later (defer).
- Expression* call_;
- // The type used for a struct to pass to a thunk, if this is not a
- // simple call.
- Struct_type* struct_type_;
-};
-
-// A go statement.
-
-class Go_statement : public Thunk_statement
-{
- public:
- Go_statement(Call_expression* call, Location location)
- : Thunk_statement(STATEMENT_GO, call, location)
- { }
-
- protected:
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-};
-
-// A defer statement.
-
-class Defer_statement : public Thunk_statement
-{
- public:
- Defer_statement(Call_expression* call, Location location)
- : Thunk_statement(STATEMENT_DEFER, call, location)
- { }
-
- protected:
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-};
-
-// A label statement.
-
-class Label_statement : public Statement
-{
- public:
- Label_statement(Label* label, Location location)
- : Statement(STATEMENT_LABEL, location),
- label_(label)
- { }
-
- // Return the label itself.
- const Label*
- label() const
- { return this->label_; }
-
- protected:
- int
- do_traverse(Traverse*);
-
- Bstatement*
- do_get_backend(Translate_context*);
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The label.
- Label* label_;
-};
-
-// A for statement.
-
-class For_statement : public Statement
-{
- public:
- For_statement(Block* init, Expression* cond, Block* post,
- Location location)
- : Statement(STATEMENT_FOR, location),
- init_(init), cond_(cond), post_(post), statements_(NULL),
- break_label_(NULL), continue_label_(NULL)
- { }
-
- // Add the statements.
- void
- add_statements(Block* statements)
- {
- go_assert(this->statements_ == NULL);
- this->statements_ = statements;
- }
-
- // Return the break label for this for statement.
- Unnamed_label*
- break_label();
-
- // Return the continue label for this for statement.
- Unnamed_label*
- continue_label();
-
- // Set the break and continue labels for this statement.
- void
- set_break_continue_labels(Unnamed_label* break_label,
- Unnamed_label* continue_label);
-
- protected:
- int
- do_traverse(Traverse*);
-
- bool
- do_traverse_assignments(Traverse_assignments*)
- { go_unreachable(); }
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The initialization statements. This may be NULL.
- Block* init_;
- // The condition. This may be NULL.
- Expression* cond_;
- // The statements to run after each iteration. This may be NULL.
- Block* post_;
- // The statements in the loop itself.
- Block* statements_;
- // The break label, if needed.
- Unnamed_label* break_label_;
- // The continue label, if needed.
- Unnamed_label* continue_label_;
-};
-
-// A for statement over a range clause.
-
-class For_range_statement : public Statement
-{
- public:
- For_range_statement(Expression* index_var, Expression* value_var,
- Expression* range, Location location)
- : Statement(STATEMENT_FOR_RANGE, location),
- index_var_(index_var), value_var_(value_var), range_(range),
- statements_(NULL), break_label_(NULL), continue_label_(NULL)
- { }
-
- // Add the statements.
- void
- add_statements(Block* statements)
- {
- go_assert(this->statements_ == NULL);
- this->statements_ = statements;
- }
-
- // Return the break label for this for statement.
- Unnamed_label*
- break_label();
-
- // Return the continue label for this for statement.
- Unnamed_label*
- continue_label();
-
- protected:
- int
- do_traverse(Traverse*);
-
- bool
- do_traverse_assignments(Traverse_assignments*)
- { go_unreachable(); }
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- Expression*
- make_range_ref(Named_object*, Temporary_statement*, Location);
-
- Expression*
- call_builtin(Gogo*, const char* funcname, Expression* arg, Location);
-
- void
- lower_range_array(Gogo*, Block*, Block*, Named_object*, Temporary_statement*,
- Temporary_statement*, Temporary_statement*,
- Block**, Expression**, Block**, Block**);
-
- void
- lower_range_slice(Gogo*, Block*, Block*, Named_object*, Temporary_statement*,
- Temporary_statement*, Temporary_statement*,
- Block**, Expression**, Block**, Block**);
-
- void
- lower_range_string(Gogo*, Block*, Block*, Named_object*, Temporary_statement*,
- Temporary_statement*, Temporary_statement*,
- Block**, Expression**, Block**, Block**);
-
- void
- lower_range_map(Gogo*, Block*, Block*, Named_object*, Temporary_statement*,
- Temporary_statement*, Temporary_statement*,
- Block**, Expression**, Block**, Block**);
-
- void
- lower_range_channel(Gogo*, Block*, Block*, Named_object*,
- Temporary_statement*, Temporary_statement*,
- Temporary_statement*, Block**, Expression**, Block**,
- Block**);
-
- // The variable which is set to the index value.
- Expression* index_var_;
- // The variable which is set to the element value. This may be
- // NULL.
- Expression* value_var_;
- // The expression we are ranging over.
- Expression* range_;
- // The statements in the block.
- Block* statements_;
- // The break label, if needed.
- Unnamed_label* break_label_;
- // The continue label, if needed.
- Unnamed_label* continue_label_;
-};
-
-// Class Case_clauses holds the clauses of a switch statement. This
-// is built by the parser.
-
-class Case_clauses
-{
- public:
- Case_clauses()
- : clauses_()
- { }
-
- // Add a new clause. CASES is a list of case expressions; it may be
- // NULL. IS_DEFAULT is true if this is the default case.
- // STATEMENTS is a block of statements. IS_FALLTHROUGH is true if
- // after the statements the case clause should fall through to the
- // next clause.
- void
- add(Expression_list* cases, bool is_default, Block* statements,
- bool is_fallthrough, Location location)
- {
- this->clauses_.push_back(Case_clause(cases, is_default, statements,
- is_fallthrough, location));
- }
-
- // Return whether there are no clauses.
- bool
- empty() const
- { return this->clauses_.empty(); }
-
- // Traverse the case clauses.
- int
- traverse(Traverse*);
-
- // Lower for a nonconstant switch.
- void
- lower(Block*, Temporary_statement*, Unnamed_label*) const;
-
- // Determine types of expressions. The Type parameter is the type
- // of the switch value.
- void
- determine_types(Type*);
-
- // Check types. The Type parameter is the type of the switch value.
- bool
- check_types(Type*);
-
- // Return true if all the clauses are constant values.
- bool
- is_constant() const;
-
- // Return true if these clauses may fall through to the statements
- // following the switch statement.
- bool
- may_fall_through() const;
-
- // Return the body of a SWITCH_EXPR when all the clauses are
- // constants.
- void
- get_backend(Translate_context*, Unnamed_label* break_label,
- std::vector<std::vector<Bexpression*> >* all_cases,
- std::vector<Bstatement*>* all_statements) const;
-
- // Dump the AST representation to a dump context.
- void
- dump_clauses(Ast_dump_context*) const;
-
- private:
- // For a constant switch we need to keep a record of constants we
- // have already seen.
- class Hash_integer_value;
- class Eq_integer_value;
- typedef Unordered_set_hash(Expression*, Hash_integer_value,
- Eq_integer_value) Case_constants;
-
- // One case clause.
- class Case_clause
- {
- public:
- Case_clause()
- : cases_(NULL), statements_(NULL), is_default_(false),
- is_fallthrough_(false), location_(UNKNOWN_LOCATION)
- { }
-
- Case_clause(Expression_list* cases, bool is_default, Block* statements,
- bool is_fallthrough, Location location)
- : cases_(cases), statements_(statements), is_default_(is_default),
- is_fallthrough_(is_fallthrough), location_(location)
- { }
-
- // Whether this clause falls through to the next clause.
- bool
- is_fallthrough() const
- { return this->is_fallthrough_; }
-
- // Whether this is the default.
- bool
- is_default() const
- { return this->is_default_; }
-
- // The location of this clause.
- Location
- location() const
- { return this->location_; }
-
- // Traversal.
- int
- traverse(Traverse*);
-
- // Lower for a nonconstant switch.
- void
- lower(Block*, Temporary_statement*, Unnamed_label*, Unnamed_label*) const;
-
- // Determine types.
- void
- determine_types(Type*);
-
- // Check types.
- bool
- check_types(Type*);
-
- // Return true if all the case expressions are constant.
- bool
- is_constant() const;
-
- // Return true if this clause may fall through to execute the
- // statements following the switch statement. This is not the
- // same as whether this clause falls through to the next clause.
- bool
- may_fall_through() const;
-
- // Convert the case values and statements to the backend
- // representation.
- Bstatement*
- get_backend(Translate_context*, Unnamed_label* break_label,
- Case_constants*, std::vector<Bexpression*>* cases) const;
-
- // Dump the AST representation to a dump context.
- void
- dump_clause(Ast_dump_context*) const;
-
- private:
- // The list of case expressions.
- Expression_list* cases_;
- // The statements to execute.
- Block* statements_;
- // Whether this is the default case.
- bool is_default_;
- // Whether this falls through after the statements.
- bool is_fallthrough_;
- // The location of this case clause.
- Location location_;
- };
-
- friend class Case_clause;
-
- // The type of the list of clauses.
- typedef std::vector<Case_clause> Clauses;
-
- // All the case clauses.
- Clauses clauses_;
-};
-
-// A switch statement.
-
-class Switch_statement : public Statement
-{
- public:
- Switch_statement(Expression* val, Location location)
- : Statement(STATEMENT_SWITCH, location),
- val_(val), clauses_(NULL), break_label_(NULL)
- { }
-
- // Add the clauses.
- void
- add_clauses(Case_clauses* clauses)
- {
- go_assert(this->clauses_ == NULL);
- this->clauses_ = clauses;
- }
-
- // Return the break label for this switch statement.
- Unnamed_label*
- break_label();
-
- protected:
- int
- do_traverse(Traverse*);
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The value to switch on. This may be NULL.
- Expression* val_;
- // The case clauses.
- Case_clauses* clauses_;
- // The break label, if needed.
- Unnamed_label* break_label_;
-};
-
-// Class Type_case_clauses holds the clauses of a type switch
-// statement. This is built by the parser.
-
-class Type_case_clauses
-{
- public:
- Type_case_clauses()
- : clauses_()
- { }
-
- // Add a new clause. TYPE is the type for this clause; it may be
- // NULL. IS_FALLTHROUGH is true if this falls through to the next
- // clause; in this case STATEMENTS will be NULL. IS_DEFAULT is true
- // if this is the default case. STATEMENTS is a block of
- // statements; it may be NULL.
- void
- add(Type* type, bool is_fallthrough, bool is_default, Block* statements,
- Location location)
- {
- this->clauses_.push_back(Type_case_clause(type, is_fallthrough, is_default,
- statements, location));
- }
-
- // Return whether there are no clauses.
- bool
- empty() const
- { return this->clauses_.empty(); }
-
- // Traverse the type case clauses.
- int
- traverse(Traverse*);
-
- // Check for duplicates.
- void
- check_duplicates() const;
-
- // Lower to if and goto statements.
- void
- lower(Type*, Block*, Temporary_statement* descriptor_temp,
- Unnamed_label* break_label) const;
-
- // Dump the AST representation to a dump context.
- void
- dump_clauses(Ast_dump_context*) const;
-
- private:
- // One type case clause.
- class Type_case_clause
- {
- public:
- Type_case_clause()
- : type_(NULL), statements_(NULL), is_default_(false),
- location_(UNKNOWN_LOCATION)
- { }
-
- Type_case_clause(Type* type, bool is_fallthrough, bool is_default,
- Block* statements, Location location)
- : type_(type), statements_(statements), is_fallthrough_(is_fallthrough),
- is_default_(is_default), location_(location)
- { }
-
- // The type.
- Type*
- type() const
- { return this->type_; }
-
- // Whether this is the default.
- bool
- is_default() const
- { return this->is_default_; }
-
- // The location of this type clause.
- Location
- location() const
- { return this->location_; }
-
- // Traversal.
- int
- traverse(Traverse*);
-
- // Lower to if and goto statements.
- void
- lower(Type*, Block*, Temporary_statement* descriptor_temp,
- Unnamed_label* break_label, Unnamed_label** stmts_label) const;
-
- // Dump the AST representation to a dump context.
- void
- dump_clause(Ast_dump_context*) const;
-
- private:
- // The type for this type clause.
- Type* type_;
- // The statements to execute.
- Block* statements_;
- // Whether this falls through--this is true for "case T1, T2".
- bool is_fallthrough_;
- // Whether this is the default case.
- bool is_default_;
- // The location of this type case clause.
- Location location_;
- };
-
- friend class Type_case_clause;
-
- // The type of the list of type clauses.
- typedef std::vector<Type_case_clause> Type_clauses;
-
- // All the type case clauses.
- Type_clauses clauses_;
-};
-
-// A type switch statement.
-
-class Type_switch_statement : public Statement
-{
- public:
- Type_switch_statement(Named_object* var, Expression* expr,
- Location location)
- : Statement(STATEMENT_TYPE_SWITCH, location),
- var_(var), expr_(expr), clauses_(NULL), break_label_(NULL)
- { go_assert(var == NULL || expr == NULL); }
-
- // Add the clauses.
- void
- add_clauses(Type_case_clauses* clauses)
- {
- go_assert(this->clauses_ == NULL);
- this->clauses_ = clauses;
- }
-
- // Return the break label for this type switch statement.
- Unnamed_label*
- break_label();
-
- protected:
- int
- do_traverse(Traverse*);
-
- Statement*
- do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
-
- Bstatement*
- do_get_backend(Translate_context*)
- { go_unreachable(); }
-
- void
- do_dump_statement(Ast_dump_context*) const;
-
- private:
- // The variable holding the value we are switching on.
- Named_object* var_;
- // The expression we are switching on if there is no variable.
- Expression* expr_;
- // The type case clauses.
- Type_case_clauses* clauses_;
- // The break label, if needed.
- Unnamed_label* break_label_;
-};
-
-#endif // !defined(GO_STATEMENTS_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/string-dump.h b/gcc-4.8.1/gcc/go/gofrontend/string-dump.h
deleted file mode 100644
index fe4807d16..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/string-dump.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// string-dump.h -- Abstract base class for dumping strings. -*- C++ -*-
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_STRING_DUMP_H
-#define GO_STRING_DUMP_H
-
-// This abstract class provides an interface strings for whatever purpose.
-// Used for example for exporting and dumping objects.
-
-class String_dump
-{
- public:
- // Write a string. Implements the String_dump interface.
- virtual void
- write_string(const std::string& s) = 0;
-
- // Implementors should override this member, to dump a formatted c string.
- virtual void
- write_c_string(const char*) = 0;
-};
-
-#endif // GO_STRING_DUMP_H
diff --git a/gcc-4.8.1/gcc/go/gofrontend/types.cc b/gcc-4.8.1/gcc/go/gofrontend/types.cc
deleted file mode 100644
index 769498282..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/types.cc
+++ /dev/null
@@ -1,9819 +0,0 @@
-// types.cc -- Go frontend types.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "toplev.h"
-#include "intl.h"
-#include "tree.h"
-#include "gimple.h"
-#include "real.h"
-#include "convert.h"
-
-#include "go-c.h"
-#include "gogo.h"
-#include "operator.h"
-#include "expressions.h"
-#include "statements.h"
-#include "export.h"
-#include "import.h"
-#include "backend.h"
-#include "types.h"
-
-// Forward declarations so that we don't have to make types.h #include
-// backend.h.
-
-static void
-get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
- bool use_placeholder,
- std::vector<Backend::Btyped_identifier>* bfields);
-
-static void
-get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder,
- std::vector<Backend::Btyped_identifier>* bfields);
-
-static void
-get_backend_interface_fields(Gogo* gogo, Interface_type* type,
- bool use_placeholder,
- std::vector<Backend::Btyped_identifier>* bfields);
-
-// Class Type.
-
-Type::Type(Type_classification classification)
- : classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
-{
-}
-
-Type::~Type()
-{
-}
-
-// Get the base type for a type--skip names and forward declarations.
-
-Type*
-Type::base()
-{
- switch (this->classification_)
- {
- case TYPE_NAMED:
- return this->named_type()->named_base();
- case TYPE_FORWARD:
- return this->forward_declaration_type()->real_type()->base();
- default:
- return this;
- }
-}
-
-const Type*
-Type::base() const
-{
- switch (this->classification_)
- {
- case TYPE_NAMED:
- return this->named_type()->named_base();
- case TYPE_FORWARD:
- return this->forward_declaration_type()->real_type()->base();
- default:
- return this;
- }
-}
-
-// Skip defined forward declarations.
-
-Type*
-Type::forwarded()
-{
- Type* t = this;
- Forward_declaration_type* ftype = t->forward_declaration_type();
- while (ftype != NULL && ftype->is_defined())
- {
- t = ftype->real_type();
- ftype = t->forward_declaration_type();
- }
- return t;
-}
-
-const Type*
-Type::forwarded() const
-{
- const Type* t = this;
- const Forward_declaration_type* ftype = t->forward_declaration_type();
- while (ftype != NULL && ftype->is_defined())
- {
- t = ftype->real_type();
- ftype = t->forward_declaration_type();
- }
- return t;
-}
-
-// If this is a named type, return it. Otherwise, return NULL.
-
-Named_type*
-Type::named_type()
-{
- return this->forwarded()->convert_no_base<Named_type, TYPE_NAMED>();
-}
-
-const Named_type*
-Type::named_type() const
-{
- return this->forwarded()->convert_no_base<const Named_type, TYPE_NAMED>();
-}
-
-// Return true if this type is not defined.
-
-bool
-Type::is_undefined() const
-{
- return this->forwarded()->forward_declaration_type() != NULL;
-}
-
-// Return true if this is a basic type: a type which is not composed
-// of other types, and is not void.
-
-bool
-Type::is_basic_type() const
-{
- switch (this->classification_)
- {
- case TYPE_INTEGER:
- case TYPE_FLOAT:
- case TYPE_COMPLEX:
- case TYPE_BOOLEAN:
- case TYPE_STRING:
- case TYPE_NIL:
- return true;
-
- case TYPE_ERROR:
- case TYPE_VOID:
- case TYPE_FUNCTION:
- case TYPE_POINTER:
- case TYPE_STRUCT:
- case TYPE_ARRAY:
- case TYPE_MAP:
- case TYPE_CHANNEL:
- case TYPE_INTERFACE:
- return false;
-
- case TYPE_NAMED:
- case TYPE_FORWARD:
- return this->base()->is_basic_type();
-
- default:
- go_unreachable();
- }
-}
-
-// Return true if this is an abstract type.
-
-bool
-Type::is_abstract() const
-{
- switch (this->classification())
- {
- case TYPE_INTEGER:
- return this->integer_type()->is_abstract();
- case TYPE_FLOAT:
- return this->float_type()->is_abstract();
- case TYPE_COMPLEX:
- return this->complex_type()->is_abstract();
- case TYPE_STRING:
- return this->is_abstract_string_type();
- case TYPE_BOOLEAN:
- return this->is_abstract_boolean_type();
- default:
- return false;
- }
-}
-
-// Return a non-abstract version of an abstract type.
-
-Type*
-Type::make_non_abstract_type()
-{
- go_assert(this->is_abstract());
- switch (this->classification())
- {
- case TYPE_INTEGER:
- if (this->integer_type()->is_rune())
- return Type::lookup_integer_type("int32");
- else
- return Type::lookup_integer_type("int");
- case TYPE_FLOAT:
- return Type::lookup_float_type("float64");
- case TYPE_COMPLEX:
- return Type::lookup_complex_type("complex128");
- case TYPE_STRING:
- return Type::lookup_string_type();
- case TYPE_BOOLEAN:
- return Type::lookup_bool_type();
- default:
- go_unreachable();
- }
-}
-
-// Return true if this is an error type. Don't give an error if we
-// try to dereference an undefined forwarding type, as this is called
-// in the parser when the type may legitimately be undefined.
-
-bool
-Type::is_error_type() const
-{
- const Type* t = this->forwarded();
- // Note that we return false for an undefined forward type.
- switch (t->classification_)
- {
- case TYPE_ERROR:
- return true;
- case TYPE_NAMED:
- return t->named_type()->is_named_error_type();
- default:
- return false;
- }
-}
-
-// If this is a pointer type, return the type to which it points.
-// Otherwise, return NULL.
-
-Type*
-Type::points_to() const
-{
- const Pointer_type* ptype = this->convert<const Pointer_type,
- TYPE_POINTER>();
- return ptype == NULL ? NULL : ptype->points_to();
-}
-
-// Return whether this is an open array type.
-
-bool
-Type::is_slice_type() const
-{
- return this->array_type() != NULL && this->array_type()->length() == NULL;
-}
-
-// Return whether this is the predeclared constant nil being used as a
-// type.
-
-bool
-Type::is_nil_constant_as_type() const
-{
- const Type* t = this->forwarded();
- if (t->forward_declaration_type() != NULL)
- {
- const Named_object* no = t->forward_declaration_type()->named_object();
- if (no->is_unknown())
- no = no->unknown_value()->real_named_object();
- if (no != NULL
- && no->is_const()
- && no->const_value()->expr()->is_nil_expression())
- return true;
- }
- return false;
-}
-
-// Traverse a type.
-
-int
-Type::traverse(Type* type, Traverse* traverse)
-{
- go_assert((traverse->traverse_mask() & Traverse::traverse_types) != 0
- || (traverse->traverse_mask()
- & Traverse::traverse_expressions) != 0);
- if (traverse->remember_type(type))
- {
- // We have already traversed this type.
- return TRAVERSE_CONTINUE;
- }
- if ((traverse->traverse_mask() & Traverse::traverse_types) != 0)
- {
- int t = traverse->type(type);
- if (t == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- else if (t == TRAVERSE_SKIP_COMPONENTS)
- return TRAVERSE_CONTINUE;
- }
- // An array type has an expression which we need to traverse if
- // traverse_expressions is set.
- if (type->do_traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Default implementation for do_traverse for child class.
-
-int
-Type::do_traverse(Traverse*)
-{
- return TRAVERSE_CONTINUE;
-}
-
-// 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, bool errors_are_identical,
- std::string* reason)
-{
- if (t1 == NULL || t2 == NULL)
- {
- // Something is wrong.
- return errors_are_identical ? true : t1 == t2;
- }
-
- // Skip defined forward declarations.
- t1 = t1->forwarded();
- t2 = t2->forwarded();
-
- // Ignore aliases for purposes of type identity.
- if (t1->named_type() != NULL && t1->named_type()->is_alias())
- t1 = t1->named_type()->real_type();
- if (t2->named_type() != NULL && t2->named_type()->is_alias())
- t2 = t2->named_type()->real_type();
-
- if (t1 == t2)
- return true;
-
- // An undefined forward declaration is an error.
- if (t1->forward_declaration_type() != NULL
- || t2->forward_declaration_type() != NULL)
- return errors_are_identical;
-
- // Avoid cascading errors with error types.
- if (t1->is_error_type() || t2->is_error_type())
- {
- 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.
- if (t1->is_sink_type() || t2->is_sink_type())
- {
- if (reason != NULL)
- *reason = "invalid use of _";
- return false;
- }
-
- // A named type is only identical to itself.
- if (t1->named_type() != NULL || t2->named_type() != NULL)
- return false;
-
- // Check type shapes.
- if (t1->classification() != t2->classification())
- return false;
-
- switch (t1->classification())
- {
- case TYPE_VOID:
- case TYPE_BOOLEAN:
- case TYPE_STRING:
- case TYPE_NIL:
- // These types are always identical.
- return true;
-
- case TYPE_INTEGER:
- return t1->integer_type()->is_identical(t2->integer_type());
-
- case TYPE_FLOAT:
- return t1->float_type()->is_identical(t2->float_type());
-
- case TYPE_COMPLEX:
- return t1->complex_type()->is_identical(t2->complex_type());
-
- 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(),
- errors_are_identical, reason);
-
- case TYPE_STRUCT:
- return t1->struct_type()->is_identical(t2->struct_type(),
- errors_are_identical);
-
- case TYPE_ARRAY:
- return t1->array_type()->is_identical(t2->array_type(),
- errors_are_identical);
-
- case TYPE_MAP:
- return t1->map_type()->is_identical(t2->map_type(),
- errors_are_identical);
-
- case TYPE_CHANNEL:
- return t1->channel_type()->is_identical(t2->channel_type(),
- errors_are_identical);
-
- case TYPE_INTERFACE:
- return t1->interface_type()->is_identical(t2->interface_type(),
- errors_are_identical);
-
- case TYPE_CALL_MULTIPLE_RESULT:
- if (reason != NULL)
- *reason = "invalid use of multiple-value function call";
- return false;
-
- default:
- go_unreachable();
- }
-}
-
-// 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, true, NULL))
- return true;
-
- // A constant of abstract bool type may be mixed with any bool type.
- if ((rhs->is_abstract_boolean_type() && lhs->is_boolean_type())
- || (lhs->is_abstract_boolean_type() && rhs->is_boolean_type()))
- return true;
-
- // A constant of abstract string type may be mixed with any string
- // type.
- if ((rhs->is_abstract_string_type() && lhs->is_string_type())
- || (lhs->is_abstract_string_type() && rhs->is_string_type()))
- return true;
-
- lhs = lhs->base();
- rhs = rhs->base();
-
- // A constant of abstract integer, float, or complex type may be
- // mixed with an integer, float, or complex type.
- if ((rhs->is_abstract()
- && (rhs->integer_type() != NULL
- || rhs->float_type() != NULL
- || rhs->complex_type() != NULL)
- && (lhs->integer_type() != NULL
- || lhs->float_type() != NULL
- || lhs->complex_type() != NULL))
- || (lhs->is_abstract()
- && (lhs->integer_type() != NULL
- || lhs->float_type() != NULL
- || lhs->complex_type() != NULL)
- && (rhs->integer_type() != NULL
- || rhs->float_type() != NULL
- || rhs->complex_type() != NULL)))
- return true;
-
- // The nil type may be compared to a pointer, an interface type, a
- // slice type, a channel type, a map type, or a function type.
- if (lhs->is_nil_type()
- && (rhs->points_to() != NULL
- || rhs->interface_type() != NULL
- || rhs->is_slice_type()
- || rhs->map_type() != NULL
- || rhs->channel_type() != NULL
- || rhs->function_type() != NULL))
- return true;
- if (rhs->is_nil_type()
- && (lhs->points_to() != NULL
- || lhs->interface_type() != NULL
- || lhs->is_slice_type()
- || lhs->map_type() != NULL
- || lhs->channel_type() != NULL
- || lhs->function_type() != NULL))
- return true;
-
- return false;
-}
-
-// Return true if a value with type T1 may be compared with a value of
-// type T2. IS_EQUALITY_OP is true for == or !=, false for <, etc.
-
-bool
-Type::are_compatible_for_comparison(bool is_equality_op, const Type *t1,
- const Type *t2, std::string *reason)
-{
- if (t1 != t2
- && !Type::are_assignable(t1, t2, NULL)
- && !Type::are_assignable(t2, t1, NULL))
- {
- if (reason != NULL)
- *reason = "incompatible types in binary expression";
- return false;
- }
-
- if (!is_equality_op)
- {
- if (t1->integer_type() == NULL
- && t1->float_type() == NULL
- && !t1->is_string_type())
- {
- if (reason != NULL)
- *reason = _("invalid comparison of non-ordered type");
- return false;
- }
- }
- else if (t1->is_slice_type()
- || t1->map_type() != NULL
- || t1->function_type() != NULL
- || t2->is_slice_type()
- || t2->map_type() != NULL
- || t2->function_type() != NULL)
- {
- if (!t1->is_nil_type() && !t2->is_nil_type())
- {
- if (reason != NULL)
- {
- if (t1->is_slice_type() || t2->is_slice_type())
- *reason = _("slice can only be compared to nil");
- else if (t1->map_type() != NULL || t2->map_type() != NULL)
- *reason = _("map can only be compared to nil");
- else
- *reason = _("func can only be compared to nil");
-
- // Match 6g error messages.
- if (t1->interface_type() != NULL || t2->interface_type() != NULL)
- {
- char buf[200];
- snprintf(buf, sizeof buf, _("invalid operation (%s)"),
- reason->c_str());
- *reason = buf;
- }
- }
- return false;
- }
- }
- else
- {
- if (!t1->is_boolean_type()
- && t1->integer_type() == NULL
- && t1->float_type() == NULL
- && t1->complex_type() == NULL
- && !t1->is_string_type()
- && t1->points_to() == NULL
- && t1->channel_type() == NULL
- && t1->interface_type() == NULL
- && t1->struct_type() == NULL
- && t1->array_type() == NULL
- && !t1->is_nil_type())
- {
- if (reason != NULL)
- *reason = _("invalid comparison of non-comparable type");
- return false;
- }
-
- if (t1->named_type() != NULL)
- return t1->named_type()->named_type_is_comparable(reason);
- else if (t2->named_type() != NULL)
- return t2->named_type()->named_type_is_comparable(reason);
- else if (t1->struct_type() != NULL)
- {
- const Struct_field_list* fields = t1->struct_type()->fields();
- for (Struct_field_list::const_iterator p = fields->begin();
- p != fields->end();
- ++p)
- {
- if (Gogo::is_sink_name(p->field_name()))
- continue;
-
- if (!p->type()->is_comparable())
- {
- if (reason != NULL)
- *reason = _("invalid comparison of non-comparable struct");
- return false;
- }
- }
- }
- else if (t1->array_type() != NULL)
- {
- if (t1->array_type()->length()->is_nil_expression()
- || !t1->array_type()->element_type()->is_comparable())
- {
- if (reason != NULL)
- *reason = _("invalid comparison of non-comparable array");
- return false;
- }
- }
- }
-
- return true;
-}
-
-// Return true if a value with type RHS may be assigned to a variable
-// with type LHS. If CHECK_HIDDEN_FIELDS is true, check whether any
-// hidden fields are modified. If REASON is not NULL, set *REASON to
-// the reason the types are not assignable.
-
-bool
-Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs,
- bool check_hidden_fields,
- std::string* reason)
-{
- // Do some checks first. Make sure the types are defined.
- if (rhs != NULL && !rhs->is_undefined())
- {
- if (rhs->is_void_type())
- {
- if (reason != NULL)
- *reason = "non-value used as value";
- return false;
- }
- if (rhs->is_call_multiple_result_type())
- {
- if (reason != NULL)
- reason->assign(_("multiple-value function call in "
- "single-value context"));
- return false;
- }
- }
-
- if (lhs != NULL && !lhs->is_undefined())
- {
- // Any value may be assigned to the blank identifier.
- if (lhs->is_sink_type())
- return true;
-
- // All fields of a struct must be exported, or the assignment
- // must be in the same package.
- if (check_hidden_fields && rhs != NULL && !rhs->is_undefined())
- {
- if (lhs->has_hidden_fields(NULL, reason)
- || rhs->has_hidden_fields(NULL, reason))
- return false;
- }
- }
-
- // Identical types are assignable.
- 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(), true, reason))
- return true;
-
- // The types are assignable if LHS is an interface type and RHS
- // implements the required methods.
- const Interface_type* lhs_interface_type = lhs->interface_type();
- if (lhs_interface_type != NULL)
- {
- if (lhs_interface_type->implements_interface(rhs, reason))
- return true;
- const Interface_type* rhs_interface_type = rhs->interface_type();
- if (rhs_interface_type != NULL
- && lhs_interface_type->is_compatible_for_assign(rhs_interface_type,
- reason))
- return true;
- }
-
- // The type are assignable if RHS is a bidirectional channel type,
- // LHS is a channel type, they have identical element types, and
- // either LHS or RHS is not a named type.
- if (lhs->channel_type() != NULL
- && rhs->channel_type() != NULL
- && rhs->channel_type()->may_send()
- && rhs->channel_type()->may_receive()
- && (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;
-
- // The nil type may be assigned to a pointer, function, slice, map,
- // channel, or interface type.
- if (rhs->is_nil_type()
- && (lhs->points_to() != NULL
- || lhs->function_type() != NULL
- || lhs->is_slice_type()
- || lhs->map_type() != NULL
- || lhs->channel_type() != NULL
- || lhs->interface_type() != NULL))
- return true;
-
- // An untyped numeric constant may be assigned to a numeric type if
- // it is representable in that type.
- if ((rhs->is_abstract()
- && (rhs->integer_type() != NULL
- || rhs->float_type() != NULL
- || rhs->complex_type() != NULL))
- && (lhs->integer_type() != NULL
- || lhs->float_type() != NULL
- || lhs->complex_type() != NULL))
- return true;
-
- // Give some better error messages.
- if (reason != NULL && reason->empty())
- {
- if (rhs->interface_type() != NULL)
- reason->assign(_("need explicit conversion"));
- else if (lhs->named_type() != NULL && rhs->named_type() != NULL)
- {
- size_t len = (lhs->named_type()->name().length()
- + rhs->named_type()->name().length()
- + 100);
- char* buf = new char[len];
- snprintf(buf, len, _("cannot use type %s as type %s"),
- rhs->named_type()->message_name().c_str(),
- lhs->named_type()->message_name().c_str());
- reason->assign(buf);
- delete[] buf;
- }
- }
-
- return false;
-}
-
-// Return true if a value with type RHS may be assigned to a variable
-// with type LHS. If REASON is not NULL, set *REASON to the reason
-// the types are not assignable.
-
-bool
-Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
-{
- return Type::are_assignable_check_hidden(lhs, rhs, false, reason);
-}
-
-// Like are_assignable but don't check for hidden fields.
-
-bool
-Type::are_assignable_hidden_ok(const Type* lhs, const Type* rhs,
- std::string* reason)
-{
- return Type::are_assignable_check_hidden(lhs, rhs, false, reason);
-}
-
-// Return true if a value with type RHS may be converted to type LHS.
-// If REASON is not NULL, set *REASON to the reason the types are not
-// convertible.
-
-bool
-Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason)
-{
- // The types are convertible if they are assignable.
- if (Type::are_assignable(lhs, rhs, reason))
- return true;
-
- // 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(), true, reason))
- return true;
-
- // The types are convertible if they are both unnamed pointer types
- // and their pointer base types have identical underlying types.
- if (lhs->named_type() == NULL
- && rhs->named_type() == NULL
- && lhs->points_to() != NULL
- && rhs->points_to() != NULL
- && (lhs->points_to()->named_type() != NULL
- || rhs->points_to()->named_type() != NULL)
- && Type::are_identical(lhs->points_to()->base(),
- rhs->points_to()->base(),
- true,
- reason))
- return true;
-
- // Integer and floating point types are convertible to each other.
- if ((lhs->integer_type() != NULL || lhs->float_type() != NULL)
- && (rhs->integer_type() != NULL || rhs->float_type() != NULL))
- return true;
-
- // Complex types are convertible to each other.
- if (lhs->complex_type() != NULL && rhs->complex_type() != NULL)
- return true;
-
- // An integer, or []byte, or []rune, may be converted to a string.
- if (lhs->is_string_type())
- {
- if (rhs->integer_type() != NULL)
- return true;
- if (rhs->is_slice_type())
- {
- const Type* e = rhs->array_type()->element_type()->forwarded();
- if (e->integer_type() != NULL
- && (e->integer_type()->is_byte()
- || e->integer_type()->is_rune()))
- return true;
- }
- }
-
- // A string may be converted to []byte or []rune.
- if (rhs->is_string_type() && lhs->is_slice_type())
- {
- const Type* e = lhs->array_type()->element_type()->forwarded();
- if (e->integer_type() != NULL
- && (e->integer_type()->is_byte() || e->integer_type()->is_rune()))
- return true;
- }
-
- // An unsafe.Pointer type may be converted to any pointer type or to
- // uintptr, and vice-versa.
- if (lhs->is_unsafe_pointer_type()
- && (rhs->points_to() != NULL
- || (rhs->integer_type() != NULL
- && rhs->forwarded() == Type::lookup_integer_type("uintptr"))))
- return true;
- if (rhs->is_unsafe_pointer_type()
- && (lhs->points_to() != NULL
- || (lhs->integer_type() != NULL
- && lhs->forwarded() == Type::lookup_integer_type("uintptr"))))
- return true;
-
- // Give a better error message.
- if (reason != NULL)
- {
- if (reason->empty())
- *reason = "invalid type conversion";
- else
- {
- std::string s = "invalid type conversion (";
- s += *reason;
- s += ')';
- *reason = s;
- }
- }
-
- return false;
-}
-
-// Return whether this type has any hidden fields. This is only a
-// possibility for a few types.
-
-bool
-Type::has_hidden_fields(const Named_type* within, std::string* reason) const
-{
- switch (this->forwarded()->classification_)
- {
- case TYPE_NAMED:
- return this->named_type()->named_type_has_hidden_fields(reason);
- case TYPE_STRUCT:
- return this->struct_type()->struct_has_hidden_fields(within, reason);
- case TYPE_ARRAY:
- return this->array_type()->array_has_hidden_fields(within, reason);
- default:
- return false;
- }
-}
-
-// Return a hash code for the type to be used for method lookup.
-
-unsigned int
-Type::hash_for_method(Gogo* gogo) const
-{
- unsigned int ret = 0;
- if (this->classification_ != TYPE_FORWARD)
- ret += this->classification_;
- return ret + this->do_hash_for_method(gogo);
-}
-
-// Default implementation of do_hash_for_method. This is appropriate
-// for types with no subfields.
-
-unsigned int
-Type::do_hash_for_method(Gogo*) const
-{
- return 0;
-}
-
-// Return a hash code for a string, given a starting hash.
-
-unsigned int
-Type::hash_string(const std::string& s, unsigned int h)
-{
- const char* p = s.data();
- size_t len = s.length();
- for (; len > 0; --len)
- {
- h ^= *p++;
- h*= 16777619;
- }
- return h;
-}
-
-// A hash table mapping unnamed types to the backend representation of
-// those types.
-
-Type::Type_btypes Type::type_btypes;
-
-// Return a tree representing this type.
-
-Btype*
-Type::get_backend(Gogo* gogo)
-{
- if (this->btype_ != NULL)
- return this->btype_;
-
- if (this->forward_declaration_type() != NULL
- || this->named_type() != NULL)
- return this->get_btype_without_hash(gogo);
-
- if (this->is_error_type())
- return gogo->backend()->error_type();
-
- // To avoid confusing the backend, translate all identical Go types
- // to the same backend representation. We use a hash table to do
- // that. There is no need to use the hash table for named types, as
- // named types are only identical to themselves.
-
- std::pair<Type*, Type_btype_entry> val;
- val.first = this;
- val.second.btype = NULL;
- val.second.is_placeholder = false;
- std::pair<Type_btypes::iterator, bool> ins =
- Type::type_btypes.insert(val);
- if (!ins.second && ins.first->second.btype != NULL)
- {
- // Note that GOGO can be NULL here, but only when the GCC
- // middle-end is asking for a frontend type. That will only
- // happen for simple types, which should never require
- // placeholders.
- if (!ins.first->second.is_placeholder)
- this->btype_ = ins.first->second.btype;
- else if (gogo->named_types_are_converted())
- {
- this->finish_backend(gogo, ins.first->second.btype);
- ins.first->second.is_placeholder = false;
- }
-
- return ins.first->second.btype;
- }
-
- Btype* bt = this->get_btype_without_hash(gogo);
-
- if (ins.first->second.btype == NULL)
- {
- ins.first->second.btype = bt;
- ins.first->second.is_placeholder = false;
- }
- else
- {
- // We have already created a backend representation for this
- // type. This can happen when an unnamed type is defined using
- // a named type which in turns uses an identical unnamed type.
- // Use the tree we created earlier and ignore the one we just
- // built.
- if (this->btype_ == bt)
- this->btype_ = ins.first->second.btype;
- bt = ins.first->second.btype;
- }
-
- return bt;
-}
-
-// Return the backend representation for a type without looking in the
-// hash table for identical types. This is used for named types,
-// since a named type is never identical to any other type.
-
-Btype*
-Type::get_btype_without_hash(Gogo* gogo)
-{
- if (this->btype_ == NULL)
- {
- Btype* bt = this->do_get_backend(gogo);
-
- // For a recursive function or pointer type, we will temporarily
- // return a circular pointer type during the recursion. We
- // don't want to record that for a forwarding type, as it may
- // confuse us later.
- if (this->forward_declaration_type() != NULL
- && gogo->backend()->is_circular_pointer_type(bt))
- return bt;
-
- if (gogo == NULL || !gogo->named_types_are_converted())
- return bt;
-
- this->btype_ = bt;
- }
- return this->btype_;
-}
-
-// Get the backend representation of a type without forcing the
-// creation of the backend representation of all supporting types.
-// This will return a backend type that has the correct size but may
-// be incomplete. E.g., a pointer will just be a placeholder pointer,
-// and will not contain the final representation of the type to which
-// it points. This is used while converting all named types to the
-// backend representation, to avoid problems with indirect references
-// to types which are not yet complete. When this is called, the
-// sizes of all direct references (e.g., a struct field) should be
-// known, but the sizes of indirect references (e.g., the type to
-// which a pointer points) may not.
-
-Btype*
-Type::get_backend_placeholder(Gogo* gogo)
-{
- if (gogo->named_types_are_converted())
- return this->get_backend(gogo);
- if (this->btype_ != NULL)
- return this->btype_;
-
- Btype* bt;
- switch (this->classification_)
- {
- case TYPE_ERROR:
- case TYPE_VOID:
- case TYPE_BOOLEAN:
- case TYPE_INTEGER:
- case TYPE_FLOAT:
- case TYPE_COMPLEX:
- case TYPE_STRING:
- case TYPE_NIL:
- // These are simple types that can just be created directly.
- return this->get_backend(gogo);
-
- case TYPE_MAP:
- case TYPE_CHANNEL:
- // All maps and channels have the same backend representation.
- return this->get_backend(gogo);
-
- case TYPE_NAMED:
- case TYPE_FORWARD:
- // Named types keep track of their own dependencies and manage
- // their own placeholders.
- return this->get_backend(gogo);
-
- case TYPE_INTERFACE:
- if (this->interface_type()->is_empty())
- return Interface_type::get_backend_empty_interface_type(gogo);
- break;
-
- default:
- break;
- }
-
- std::pair<Type*, Type_btype_entry> val;
- val.first = this;
- val.second.btype = NULL;
- val.second.is_placeholder = false;
- std::pair<Type_btypes::iterator, bool> ins =
- Type::type_btypes.insert(val);
- if (!ins.second && ins.first->second.btype != NULL)
- return ins.first->second.btype;
-
- switch (this->classification_)
- {
- case TYPE_FUNCTION:
- {
- Location loc = this->function_type()->location();
- bt = gogo->backend()->placeholder_pointer_type("", loc, true);
- }
- break;
-
- case TYPE_POINTER:
- {
- Location loc = Linemap::unknown_location();
- bt = gogo->backend()->placeholder_pointer_type("", loc, false);
- }
- break;
-
- case TYPE_STRUCT:
- // We don't have to make the struct itself be a placeholder. We
- // are promised that we know the sizes of the struct fields.
- // But we may have to use a placeholder for any particular
- // struct field.
- {
- std::vector<Backend::Btyped_identifier> bfields;
- get_backend_struct_fields(gogo, this->struct_type()->fields(),
- true, &bfields);
- bt = gogo->backend()->struct_type(bfields);
- }
- break;
-
- case TYPE_ARRAY:
- if (this->is_slice_type())
- {
- std::vector<Backend::Btyped_identifier> bfields;
- get_backend_slice_fields(gogo, this->array_type(), true, &bfields);
- bt = gogo->backend()->struct_type(bfields);
- }
- else
- {
- Btype* element = this->array_type()->get_backend_element(gogo, true);
- Bexpression* len = this->array_type()->get_backend_length(gogo);
- bt = gogo->backend()->array_type(element, len);
- }
- break;
-
- case TYPE_INTERFACE:
- {
- go_assert(!this->interface_type()->is_empty());
- std::vector<Backend::Btyped_identifier> bfields;
- get_backend_interface_fields(gogo, this->interface_type(), true,
- &bfields);
- bt = gogo->backend()->struct_type(bfields);
- }
- break;
-
- case TYPE_SINK:
- case TYPE_CALL_MULTIPLE_RESULT:
- /* Note that various classifications were handled in the earlier
- switch. */
- default:
- go_unreachable();
- }
-
- if (ins.first->second.btype == NULL)
- {
- ins.first->second.btype = bt;
- ins.first->second.is_placeholder = true;
- }
- else
- {
- // A placeholder for this type got created along the way. Use
- // that one and ignore the one we just built.
- bt = ins.first->second.btype;
- }
-
- return bt;
-}
-
-// Complete the backend representation. This is called for a type
-// using a placeholder type.
-
-void
-Type::finish_backend(Gogo* gogo, Btype *placeholder)
-{
- switch (this->classification_)
- {
- case TYPE_ERROR:
- case TYPE_VOID:
- case TYPE_BOOLEAN:
- case TYPE_INTEGER:
- case TYPE_FLOAT:
- case TYPE_COMPLEX:
- case TYPE_STRING:
- case TYPE_NIL:
- go_unreachable();
-
- case TYPE_FUNCTION:
- {
- Btype* bt = this->do_get_backend(gogo);
- if (!gogo->backend()->set_placeholder_function_type(placeholder, bt))
- go_assert(saw_errors());
- }
- break;
-
- case TYPE_POINTER:
- {
- Btype* bt = this->do_get_backend(gogo);
- if (!gogo->backend()->set_placeholder_pointer_type(placeholder, bt))
- go_assert(saw_errors());
- }
- break;
-
- case TYPE_STRUCT:
- // The struct type itself is done, but we have to make sure that
- // all the field types are converted.
- this->struct_type()->finish_backend_fields(gogo);
- break;
-
- case TYPE_ARRAY:
- // The array type itself is done, but make sure the element type
- // is converted.
- this->array_type()->finish_backend_element(gogo);
- break;
-
- case TYPE_MAP:
- case TYPE_CHANNEL:
- go_unreachable();
-
- case TYPE_INTERFACE:
- // The interface type itself is done, but make sure the method
- // types are converted.
- this->interface_type()->finish_backend_methods(gogo);
- break;
-
- case TYPE_NAMED:
- case TYPE_FORWARD:
- go_unreachable();
-
- case TYPE_SINK:
- case TYPE_CALL_MULTIPLE_RESULT:
- default:
- go_unreachable();
- }
-
- this->btype_ = placeholder;
-}
-
-// Return a pointer to the type descriptor for this type.
-
-tree
-Type::type_descriptor_pointer(Gogo* gogo, Location location)
-{
- Type* t = this->forwarded();
- if (t->named_type() != NULL && t->named_type()->is_alias())
- t = t->named_type()->real_type();
- if (t->type_descriptor_var_ == NULL)
- {
- t->make_type_descriptor_var(gogo);
- go_assert(t->type_descriptor_var_ != NULL);
- }
- tree var_tree = var_to_tree(t->type_descriptor_var_);
- if (var_tree == error_mark_node)
- return error_mark_node;
- return build_fold_addr_expr_loc(location.gcc_location(), var_tree);
-}
-
-// A mapping from unnamed types to type descriptor variables.
-
-Type::Type_descriptor_vars Type::type_descriptor_vars;
-
-// Build the type descriptor for this type.
-
-void
-Type::make_type_descriptor_var(Gogo* gogo)
-{
- go_assert(this->type_descriptor_var_ == NULL);
-
- Named_type* nt = this->named_type();
-
- // We can have multiple instances of unnamed types, but we only want
- // to emit the type descriptor once. We use a hash table. This is
- // not necessary for named types, as they are unique, and we store
- // the type descriptor in the type itself.
- Bvariable** phash = NULL;
- if (nt == NULL)
- {
- Bvariable* bvnull = NULL;
- std::pair<Type_descriptor_vars::iterator, bool> ins =
- Type::type_descriptor_vars.insert(std::make_pair(this, bvnull));
- if (!ins.second)
- {
- // We've already build a type descriptor for this type.
- this->type_descriptor_var_ = ins.first->second;
- return;
- }
- phash = &ins.first->second;
- }
-
- std::string var_name = this->type_descriptor_var_name(gogo, nt);
-
- // Build the contents of the type descriptor.
- Expression* initializer = this->do_type_descriptor(gogo, NULL);
-
- Btype* initializer_btype = initializer->type()->get_backend(gogo);
-
- Location loc = nt == NULL ? Linemap::predeclared_location() : nt->location();
-
- const Package* dummy;
- if (this->type_descriptor_defined_elsewhere(nt, &dummy))
- {
- this->type_descriptor_var_ =
- gogo->backend()->immutable_struct_reference(var_name,
- initializer_btype,
- loc);
- if (phash != NULL)
- *phash = this->type_descriptor_var_;
- return;
- }
-
- // See if this type descriptor can appear in multiple packages.
- bool is_common = false;
- if (nt != NULL)
- {
- // We create the descriptor for a builtin type whenever we need
- // it.
- is_common = nt->is_builtin();
- }
- else
- {
- // This is an unnamed type. The descriptor could be defined in
- // any package where it is needed, and the linker will pick one
- // descriptor to keep.
- is_common = true;
- }
-
- // We are going to build the type descriptor in this package. We
- // must create the variable before we convert the initializer to the
- // backend representation, because the initializer may refer to the
- // type descriptor of this type. By setting type_descriptor_var_ we
- // ensure that type_descriptor_pointer will work if called while
- // converting INITIALIZER.
-
- this->type_descriptor_var_ =
- gogo->backend()->immutable_struct(var_name, is_common, initializer_btype,
- loc);
- if (phash != NULL)
- *phash = this->type_descriptor_var_;
-
- Translate_context context(gogo, NULL, NULL, NULL);
- context.set_is_const();
- Bexpression* binitializer = tree_to_expr(initializer->get_tree(&context));
-
- gogo->backend()->immutable_struct_set_init(this->type_descriptor_var_,
- var_name, is_common,
- initializer_btype, loc,
- binitializer);
-}
-
-// Return the name of the type descriptor variable. If NT is not
-// NULL, use it to get the name. Otherwise this is an unnamed type.
-
-std::string
-Type::type_descriptor_var_name(Gogo* gogo, Named_type* nt)
-{
- if (nt == NULL)
- return "__go_td_" + this->mangled_name(gogo);
-
- Named_object* no = nt->named_object();
- unsigned int index;
- const Named_object* in_function = nt->in_function(&index);
- std::string ret = "__go_tdn_";
- if (nt->is_builtin())
- go_assert(in_function == NULL);
- else
- {
- const std::string& pkgpath(no->package() == NULL
- ? gogo->pkgpath_symbol()
- : no->package()->pkgpath_symbol());
- ret.append(pkgpath);
- ret.append(1, '.');
- if (in_function != NULL)
- {
- ret.append(Gogo::unpack_hidden_name(in_function->name()));
- ret.append(1, '.');
- if (index > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", index);
- ret.append(buf);
- ret.append(1, '.');
- }
- }
- }
-
- // FIXME: This adds in pkgpath twice for hidden symbols, which is
- // pointless.
- const std::string& name(no->name());
- if (!Gogo::is_hidden_name(name))
- ret.append(name);
- else
- {
- ret.append(1, '.');
- ret.append(Gogo::pkgpath_for_symbol(Gogo::hidden_name_pkgpath(name)));
- ret.append(1, '.');
- ret.append(Gogo::unpack_hidden_name(name));
- }
-
- return ret;
-}
-
-// Return true if this type descriptor is defined in a different
-// package. If this returns true it sets *PACKAGE to the package.
-
-bool
-Type::type_descriptor_defined_elsewhere(Named_type* nt,
- const Package** package)
-{
- if (nt != NULL)
- {
- if (nt->named_object()->package() != NULL)
- {
- // This is a named type defined in a different package. The
- // type descriptor should be defined in that package.
- *package = nt->named_object()->package();
- return true;
- }
- }
- else
- {
- if (this->points_to() != NULL
- && this->points_to()->named_type() != NULL
- && this->points_to()->named_type()->named_object()->package() != NULL)
- {
- // This is an unnamed pointer to a named type defined in a
- // different package. The descriptor should be defined in
- // that package.
- *package = this->points_to()->named_type()->named_object()->package();
- return true;
- }
- }
- return false;
-}
-
-// Return a composite literal for a type descriptor.
-
-Expression*
-Type::type_descriptor(Gogo* gogo, Type* type)
-{
- return type->do_type_descriptor(gogo, NULL);
-}
-
-// Return a composite literal for a type descriptor with a name.
-
-Expression*
-Type::named_type_descriptor(Gogo* gogo, Type* type, Named_type* name)
-{
- go_assert(name != NULL && type->named_type() != name);
- return type->do_type_descriptor(gogo, name);
-}
-
-// Make a builtin struct type from a list of fields. The fields are
-// pairs of a name and a type.
-
-Struct_type*
-Type::make_builtin_struct_type(int nfields, ...)
-{
- va_list ap;
- va_start(ap, nfields);
-
- Location bloc = Linemap::predeclared_location();
- Struct_field_list* sfl = new Struct_field_list();
- for (int i = 0; i < nfields; i++)
- {
- const char* field_name = va_arg(ap, const char *);
- Type* type = va_arg(ap, Type*);
- sfl->push_back(Struct_field(Typed_identifier(field_name, type, bloc)));
- }
-
- va_end(ap);
-
- return Type::make_struct_type(sfl, bloc);
-}
-
-// A list of builtin named types.
-
-std::vector<Named_type*> Type::named_builtin_types;
-
-// Make a builtin named type.
-
-Named_type*
-Type::make_builtin_named_type(const char* name, Type* type)
-{
- Location bloc = Linemap::predeclared_location();
- Named_object* no = Named_object::make_type(name, NULL, type, bloc);
- Named_type* ret = no->type_value();
- Type::named_builtin_types.push_back(ret);
- return ret;
-}
-
-// Convert the named builtin types.
-
-void
-Type::convert_builtin_named_types(Gogo* gogo)
-{
- for (std::vector<Named_type*>::const_iterator p =
- Type::named_builtin_types.begin();
- p != Type::named_builtin_types.end();
- ++p)
- {
- bool r = (*p)->verify();
- go_assert(r);
- (*p)->convert(gogo);
- }
-}
-
-// Return the type of a type descriptor. We should really tie this to
-// runtime.Type rather than copying it. This must match commonType in
-// libgo/go/runtime/type.go.
-
-Type*
-Type::make_type_descriptor_type()
-{
- static Type* ret;
- if (ret == NULL)
- {
- Location bloc = Linemap::predeclared_location();
-
- Type* uint8_type = Type::lookup_integer_type("uint8");
- Type* uint32_type = Type::lookup_integer_type("uint32");
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
- Type* string_type = Type::lookup_string_type();
- Type* pointer_string_type = Type::make_pointer_type(string_type);
-
- // This is an unnamed version of unsafe.Pointer. Perhaps we
- // should use the named version instead, although that would
- // require us to create the unsafe package if it has not been
- // imported. It probably doesn't matter.
- Type* void_type = Type::make_void_type();
- Type* unsafe_pointer_type = Type::make_pointer_type(void_type);
-
- // Forward declaration for the type descriptor type.
- Named_object* named_type_descriptor_type =
- Named_object::make_type_declaration("commonType", NULL, bloc);
- Type* ft = Type::make_forward_declaration(named_type_descriptor_type);
- Type* pointer_type_descriptor_type = Type::make_pointer_type(ft);
-
- // The type of a method on a concrete type.
- Struct_type* method_type =
- Type::make_builtin_struct_type(5,
- "name", pointer_string_type,
- "pkgPath", pointer_string_type,
- "mtyp", pointer_type_descriptor_type,
- "typ", pointer_type_descriptor_type,
- "tfn", unsafe_pointer_type);
- Named_type* named_method_type =
- Type::make_builtin_named_type("method", method_type);
-
- // Information for types with a name or methods.
- Type* slice_named_method_type =
- Type::make_array_type(named_method_type, NULL);
- Struct_type* uncommon_type =
- Type::make_builtin_struct_type(3,
- "name", pointer_string_type,
- "pkgPath", pointer_string_type,
- "methods", slice_named_method_type);
- Named_type* named_uncommon_type =
- Type::make_builtin_named_type("uncommonType", uncommon_type);
-
- Type* pointer_uncommon_type =
- Type::make_pointer_type(named_uncommon_type);
-
- // The type descriptor type.
-
- Typed_identifier_list* params = new Typed_identifier_list();
- params->push_back(Typed_identifier("key", unsafe_pointer_type, bloc));
- params->push_back(Typed_identifier("key_size", uintptr_type, bloc));
-
- Typed_identifier_list* results = new Typed_identifier_list();
- results->push_back(Typed_identifier("", uintptr_type, bloc));
-
- Type* hashfn_type = Type::make_function_type(NULL, params, results, bloc);
-
- params = new Typed_identifier_list();
- params->push_back(Typed_identifier("key1", unsafe_pointer_type, bloc));
- params->push_back(Typed_identifier("key2", unsafe_pointer_type, bloc));
- params->push_back(Typed_identifier("key_size", uintptr_type, bloc));
-
- results = new Typed_identifier_list();
- results->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc));
-
- Type* equalfn_type = Type::make_function_type(NULL, params, results,
- bloc);
-
- Struct_type* type_descriptor_type =
- Type::make_builtin_struct_type(10,
- "Kind", uint8_type,
- "align", uint8_type,
- "fieldAlign", uint8_type,
- "size", uintptr_type,
- "hash", uint32_type,
- "hashfn", hashfn_type,
- "equalfn", equalfn_type,
- "string", pointer_string_type,
- "", pointer_uncommon_type,
- "ptrToThis",
- pointer_type_descriptor_type);
-
- Named_type* named = Type::make_builtin_named_type("commonType",
- type_descriptor_type);
-
- named_type_descriptor_type->set_type_value(named);
-
- ret = named;
- }
-
- return ret;
-}
-
-// Make the type of a pointer to a type descriptor as represented in
-// Go.
-
-Type*
-Type::make_type_descriptor_ptr_type()
-{
- static Type* ret;
- if (ret == NULL)
- ret = Type::make_pointer_type(Type::make_type_descriptor_type());
- return ret;
-}
-
-// Set *HASH_FN and *EQUAL_FN to the runtime functions which compute a
-// hash code for this type and which compare whether two values of
-// this type are equal. If NAME is not NULL it is the name of this
-// type. HASH_FNTYPE and EQUAL_FNTYPE are the types of these
-// functions, for convenience; they may be NULL.
-
-void
-Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype,
- Function_type* equal_fntype, Named_object** hash_fn,
- Named_object** equal_fn)
-{
- if (hash_fntype == NULL || equal_fntype == NULL)
- {
- Location bloc = Linemap::predeclared_location();
-
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
- Type* void_type = Type::make_void_type();
- Type* unsafe_pointer_type = Type::make_pointer_type(void_type);
-
- if (hash_fntype == NULL)
- {
- Typed_identifier_list* params = new Typed_identifier_list();
- params->push_back(Typed_identifier("key", unsafe_pointer_type,
- bloc));
- params->push_back(Typed_identifier("key_size", uintptr_type, bloc));
-
- Typed_identifier_list* results = new Typed_identifier_list();
- results->push_back(Typed_identifier("", uintptr_type, bloc));
-
- hash_fntype = Type::make_function_type(NULL, params, results, bloc);
- }
- if (equal_fntype == NULL)
- {
- Typed_identifier_list* params = new Typed_identifier_list();
- params->push_back(Typed_identifier("key1", unsafe_pointer_type,
- bloc));
- params->push_back(Typed_identifier("key2", unsafe_pointer_type,
- bloc));
- params->push_back(Typed_identifier("key_size", uintptr_type, bloc));
-
- Typed_identifier_list* results = new Typed_identifier_list();
- results->push_back(Typed_identifier("", Type::lookup_bool_type(),
- bloc));
-
- equal_fntype = Type::make_function_type(NULL, params, results, bloc);
- }
- }
-
- const char* hash_fnname;
- const char* equal_fnname;
- if (this->compare_is_identity(gogo))
- {
- hash_fnname = "__go_type_hash_identity";
- equal_fnname = "__go_type_equal_identity";
- }
- else if (!this->is_comparable())
- {
- hash_fnname = "__go_type_hash_error";
- equal_fnname = "__go_type_equal_error";
- }
- else
- {
- switch (this->base()->classification())
- {
- case Type::TYPE_ERROR:
- case Type::TYPE_VOID:
- case Type::TYPE_NIL:
- case Type::TYPE_FUNCTION:
- case Type::TYPE_MAP:
- // For these types is_comparable should have returned false.
- go_unreachable();
-
- case Type::TYPE_BOOLEAN:
- case Type::TYPE_INTEGER:
- case Type::TYPE_POINTER:
- case Type::TYPE_CHANNEL:
- // For these types compare_is_identity should have returned true.
- go_unreachable();
-
- case Type::TYPE_FLOAT:
- hash_fnname = "__go_type_hash_float";
- equal_fnname = "__go_type_equal_float";
- break;
-
- case Type::TYPE_COMPLEX:
- hash_fnname = "__go_type_hash_complex";
- equal_fnname = "__go_type_equal_complex";
- break;
-
- case Type::TYPE_STRING:
- hash_fnname = "__go_type_hash_string";
- equal_fnname = "__go_type_equal_string";
- break;
-
- case Type::TYPE_STRUCT:
- {
- // This is a struct which can not be compared using a
- // simple identity function. We need to build a function
- // for comparison.
- this->specific_type_functions(gogo, name, hash_fntype,
- equal_fntype, hash_fn, equal_fn);
- return;
- }
-
- case Type::TYPE_ARRAY:
- if (this->is_slice_type())
- {
- // Type::is_compatible_for_comparison should have
- // returned false.
- go_unreachable();
- }
- else
- {
- // This is an array which can not be compared using a
- // simple identity function. We need to build a
- // function for comparison.
- this->specific_type_functions(gogo, name, hash_fntype,
- equal_fntype, hash_fn, equal_fn);
- return;
- }
- break;
-
- case Type::TYPE_INTERFACE:
- if (this->interface_type()->is_empty())
- {
- hash_fnname = "__go_type_hash_empty_interface";
- equal_fnname = "__go_type_equal_empty_interface";
- }
- else
- {
- hash_fnname = "__go_type_hash_interface";
- equal_fnname = "__go_type_equal_interface";
- }
- break;
-
- case Type::TYPE_NAMED:
- case Type::TYPE_FORWARD:
- go_unreachable();
-
- default:
- go_unreachable();
- }
- }
-
-
- Location bloc = Linemap::predeclared_location();
- *hash_fn = Named_object::make_function_declaration(hash_fnname, NULL,
- hash_fntype, bloc);
- (*hash_fn)->func_declaration_value()->set_asm_name(hash_fnname);
- *equal_fn = Named_object::make_function_declaration(equal_fnname, NULL,
- equal_fntype, bloc);
- (*equal_fn)->func_declaration_value()->set_asm_name(equal_fnname);
-}
-
-// A hash table mapping types to the specific hash functions.
-
-Type::Type_functions Type::type_functions_table;
-
-// Handle a type function which is specific to a type: a struct or
-// array which can not use an identity comparison.
-
-void
-Type::specific_type_functions(Gogo* gogo, Named_type* name,
- Function_type* hash_fntype,
- Function_type* equal_fntype,
- Named_object** hash_fn,
- Named_object** equal_fn)
-{
- Hash_equal_fn fnull(NULL, NULL);
- std::pair<Type*, Hash_equal_fn> val(name != NULL ? name : this, fnull);
- std::pair<Type_functions::iterator, bool> ins =
- Type::type_functions_table.insert(val);
- if (!ins.second)
- {
- // We already have functions for this type
- *hash_fn = ins.first->second.first;
- *equal_fn = ins.first->second.second;
- return;
- }
-
- std::string base_name;
- if (name == NULL)
- {
- // Mangled names can have '.' if they happen to refer to named
- // types in some way. That's fine if this is simply a named
- // type, but otherwise it will confuse the code that builds
- // function identifiers. Remove '.' when necessary.
- base_name = this->mangled_name(gogo);
- size_t i;
- while ((i = base_name.find('.')) != std::string::npos)
- base_name[i] = '$';
- base_name = gogo->pack_hidden_name(base_name, false);
- }
- else
- {
- // This name is already hidden or not as appropriate.
- base_name = name->name();
- unsigned int index;
- const Named_object* in_function = name->in_function(&index);
- if (in_function != NULL)
- {
- base_name += '$' + Gogo::unpack_hidden_name(in_function->name());
- if (index > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", index);
- base_name += '$';
- base_name += buf;
- }
- }
- }
- std::string hash_name = base_name + "$hash";
- std::string equal_name = base_name + "$equal";
-
- Location bloc = Linemap::predeclared_location();
-
- const Package* package = NULL;
- bool is_defined_elsewhere =
- this->type_descriptor_defined_elsewhere(name, &package);
- if (is_defined_elsewhere)
- {
- *hash_fn = Named_object::make_function_declaration(hash_name, package,
- hash_fntype, bloc);
- *equal_fn = Named_object::make_function_declaration(equal_name, package,
- equal_fntype, bloc);
- }
- else
- {
- *hash_fn = gogo->declare_package_function(hash_name, hash_fntype, bloc);
- *equal_fn = gogo->declare_package_function(equal_name, equal_fntype,
- bloc);
- }
-
- ins.first->second.first = *hash_fn;
- ins.first->second.second = *equal_fn;
-
- if (!is_defined_elsewhere)
- {
- if (gogo->in_global_scope())
- this->write_specific_type_functions(gogo, name, hash_name, hash_fntype,
- equal_name, equal_fntype);
- else
- gogo->queue_specific_type_function(this, name, hash_name, hash_fntype,
- equal_name, equal_fntype);
- }
-}
-
-// Write the hash and equality functions for a type which needs to be
-// written specially.
-
-void
-Type::write_specific_type_functions(Gogo* gogo, Named_type* name,
- const std::string& hash_name,
- Function_type* hash_fntype,
- const std::string& equal_name,
- Function_type* equal_fntype)
-{
- Location bloc = Linemap::predeclared_location();
-
- if (gogo->specific_type_functions_are_written())
- {
- go_assert(saw_errors());
- return;
- }
-
- Named_object* hash_fn = gogo->start_function(hash_name, hash_fntype, false,
- bloc);
- gogo->start_block(bloc);
-
- if (this->struct_type() != NULL)
- this->struct_type()->write_hash_function(gogo, name, hash_fntype,
- equal_fntype);
- else if (this->array_type() != NULL)
- this->array_type()->write_hash_function(gogo, name, hash_fntype,
- equal_fntype);
- else
- go_unreachable();
-
- Block* b = gogo->finish_block(bloc);
- gogo->add_block(b, bloc);
- gogo->lower_block(hash_fn, b);
- gogo->finish_function(bloc);
-
- Named_object *equal_fn = gogo->start_function(equal_name, equal_fntype,
- false, bloc);
- gogo->start_block(bloc);
-
- if (this->struct_type() != NULL)
- this->struct_type()->write_equal_function(gogo, name);
- else if (this->array_type() != NULL)
- this->array_type()->write_equal_function(gogo, name);
- else
- go_unreachable();
-
- b = gogo->finish_block(bloc);
- gogo->add_block(b, bloc);
- gogo->lower_block(equal_fn, b);
- gogo->finish_function(bloc);
-}
-
-// Return a composite literal for the type descriptor for a plain type
-// of kind RUNTIME_TYPE_KIND named NAME.
-
-Expression*
-Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
- Named_type* name, const Methods* methods,
- bool only_value_methods)
-{
- Location bloc = Linemap::predeclared_location();
-
- Type* td_type = Type::make_type_descriptor_type();
- const Struct_field_list* fields = td_type->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(9);
-
- if (!this->has_pointer())
- runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS;
- Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("Kind"));
- mpz_t iv;
- mpz_init_set_ui(iv, runtime_type_kind);
- vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
-
- ++p;
- go_assert(p->is_field_name("align"));
- Expression::Type_info type_info = Expression::TYPE_INFO_ALIGNMENT;
- vals->push_back(Expression::make_type_info(this, type_info));
-
- ++p;
- go_assert(p->is_field_name("fieldAlign"));
- type_info = Expression::TYPE_INFO_FIELD_ALIGNMENT;
- vals->push_back(Expression::make_type_info(this, type_info));
-
- ++p;
- go_assert(p->is_field_name("size"));
- type_info = Expression::TYPE_INFO_SIZE;
- vals->push_back(Expression::make_type_info(this, type_info));
-
- ++p;
- go_assert(p->is_field_name("hash"));
- unsigned int h;
- if (name != NULL)
- h = name->hash_for_method(gogo);
- else
- h = this->hash_for_method(gogo);
- mpz_set_ui(iv, h);
- vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
-
- ++p;
- go_assert(p->is_field_name("hashfn"));
- Function_type* hash_fntype = p->type()->function_type();
-
- ++p;
- go_assert(p->is_field_name("equalfn"));
- Function_type* equal_fntype = p->type()->function_type();
-
- Named_object* hash_fn;
- Named_object* equal_fn;
- this->type_functions(gogo, name, hash_fntype, equal_fntype, &hash_fn,
- &equal_fn);
- vals->push_back(Expression::make_func_reference(hash_fn, NULL, bloc));
- vals->push_back(Expression::make_func_reference(equal_fn, NULL, bloc));
-
- ++p;
- go_assert(p->is_field_name("string"));
- Expression* s = Expression::make_string((name != NULL
- ? name->reflection(gogo)
- : this->reflection(gogo)),
- bloc);
- vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
-
- ++p;
- go_assert(p->is_field_name("uncommonType"));
- if (name == NULL && methods == NULL)
- vals->push_back(Expression::make_nil(bloc));
- else
- {
- if (methods == NULL)
- methods = name->methods();
- vals->push_back(this->uncommon_type_constructor(gogo,
- p->type()->deref(),
- name, methods,
- only_value_methods));
- }
-
- ++p;
- go_assert(p->is_field_name("ptrToThis"));
- if (name == NULL)
- vals->push_back(Expression::make_nil(bloc));
- else
- {
- Type* pt = Type::make_pointer_type(name);
- vals->push_back(Expression::make_type_descriptor(pt, bloc));
- }
-
- ++p;
- go_assert(p == fields->end());
-
- mpz_clear(iv);
-
- return Expression::make_struct_composite_literal(td_type, vals, bloc);
-}
-
-// Return a composite literal for the uncommon type information for
-// this type. UNCOMMON_STRUCT_TYPE is the type of the uncommon type
-// struct. If name is not NULL, it is the name of the type. If
-// METHODS is not NULL, it is the list of methods. ONLY_VALUE_METHODS
-// is true if only value methods should be included. At least one of
-// NAME and METHODS must not be NULL.
-
-Expression*
-Type::uncommon_type_constructor(Gogo* gogo, Type* uncommon_type,
- Named_type* name, const Methods* methods,
- bool only_value_methods) const
-{
- Location bloc = Linemap::predeclared_location();
-
- const Struct_field_list* fields = uncommon_type->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(3);
-
- Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("name"));
-
- ++p;
- go_assert(p->is_field_name("pkgPath"));
-
- if (name == NULL)
- {
- vals->push_back(Expression::make_nil(bloc));
- vals->push_back(Expression::make_nil(bloc));
- }
- else
- {
- Named_object* no = name->named_object();
- std::string n = Gogo::unpack_hidden_name(no->name());
- Expression* s = Expression::make_string(n, bloc);
- vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
-
- if (name->is_builtin())
- vals->push_back(Expression::make_nil(bloc));
- else
- {
- const Package* package = no->package();
- const std::string& pkgpath(package == NULL
- ? gogo->pkgpath()
- : package->pkgpath());
- n.assign(pkgpath);
- unsigned int index;
- const Named_object* in_function = name->in_function(&index);
- if (in_function != NULL)
- {
- n.append(1, '.');
- n.append(Gogo::unpack_hidden_name(in_function->name()));
- if (index > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", index);
- n.append(1, '.');
- n.append(buf);
- }
- }
- s = Expression::make_string(n, bloc);
- vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
- }
- }
-
- ++p;
- go_assert(p->is_field_name("methods"));
- vals->push_back(this->methods_constructor(gogo, p->type(), methods,
- only_value_methods));
-
- ++p;
- go_assert(p == fields->end());
-
- Expression* r = Expression::make_struct_composite_literal(uncommon_type,
- vals, bloc);
- return Expression::make_unary(OPERATOR_AND, r, bloc);
-}
-
-// Sort methods by name.
-
-class Sort_methods
-{
- public:
- bool
- operator()(const std::pair<std::string, const Method*>& m1,
- const std::pair<std::string, const Method*>& m2) const
- { return m1.first < m2.first; }
-};
-
-// Return a composite literal for the type method table for this type.
-// METHODS_TYPE is the type of the table, and is a slice type.
-// METHODS is the list of methods. If ONLY_VALUE_METHODS is true,
-// then only value methods are used.
-
-Expression*
-Type::methods_constructor(Gogo* gogo, Type* methods_type,
- const Methods* methods,
- bool only_value_methods) const
-{
- Location bloc = Linemap::predeclared_location();
-
- std::vector<std::pair<std::string, const Method*> > smethods;
- if (methods != NULL)
- {
- smethods.reserve(methods->count());
- for (Methods::const_iterator p = methods->begin();
- p != methods->end();
- ++p)
- {
- if (p->second->is_ambiguous())
- continue;
- if (only_value_methods && !p->second->is_value_method())
- continue;
-
- // This is where we implement the magic //go:nointerface
- // comment. If we saw that comment, we don't add this
- // method to the type descriptor.
- if (p->second->nointerface())
- continue;
-
- smethods.push_back(std::make_pair(p->first, p->second));
- }
- }
-
- if (smethods.empty())
- return Expression::make_slice_composite_literal(methods_type, NULL, bloc);
-
- std::sort(smethods.begin(), smethods.end(), Sort_methods());
-
- Type* method_type = methods_type->array_type()->element_type();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(smethods.size());
- for (std::vector<std::pair<std::string, const Method*> >::const_iterator p
- = smethods.begin();
- p != smethods.end();
- ++p)
- vals->push_back(this->method_constructor(gogo, method_type, p->first,
- p->second, only_value_methods));
-
- return Expression::make_slice_composite_literal(methods_type, vals, bloc);
-}
-
-// Return a composite literal for a single method. METHOD_TYPE is the
-// type of the entry. METHOD_NAME is the name of the method and M is
-// the method information.
-
-Expression*
-Type::method_constructor(Gogo*, Type* method_type,
- const std::string& method_name,
- const Method* m,
- bool only_value_methods) const
-{
- Location bloc = Linemap::predeclared_location();
-
- const Struct_field_list* fields = method_type->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(5);
-
- Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("name"));
- const std::string n = Gogo::unpack_hidden_name(method_name);
- Expression* s = Expression::make_string(n, bloc);
- vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
-
- ++p;
- go_assert(p->is_field_name("pkgPath"));
- if (!Gogo::is_hidden_name(method_name))
- vals->push_back(Expression::make_nil(bloc));
- else
- {
- s = Expression::make_string(Gogo::hidden_name_pkgpath(method_name),
- bloc);
- vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
- }
-
- Named_object* no = (m->needs_stub_method()
- ? m->stub_object()
- : m->named_object());
-
- Function_type* mtype;
- if (no->is_function())
- mtype = no->func_value()->type();
- else
- mtype = no->func_declaration_value()->type();
- go_assert(mtype->is_method());
- Type* nonmethod_type = mtype->copy_without_receiver();
-
- ++p;
- go_assert(p->is_field_name("mtyp"));
- vals->push_back(Expression::make_type_descriptor(nonmethod_type, bloc));
-
- ++p;
- go_assert(p->is_field_name("typ"));
- if (!only_value_methods && m->is_value_method())
- {
- // This is a value method on a pointer type. Change the type of
- // the method to use a pointer receiver. The implementation
- // always uses a pointer receiver anyhow.
- Type* rtype = mtype->receiver()->type();
- Type* prtype = Type::make_pointer_type(rtype);
- Typed_identifier* receiver =
- new Typed_identifier(mtype->receiver()->name(), prtype,
- mtype->receiver()->location());
- mtype = Type::make_function_type(receiver,
- (mtype->parameters() == NULL
- ? NULL
- : mtype->parameters()->copy()),
- (mtype->results() == NULL
- ? NULL
- : mtype->results()->copy()),
- mtype->location());
- }
- vals->push_back(Expression::make_type_descriptor(mtype, bloc));
-
- ++p;
- go_assert(p->is_field_name("tfn"));
- vals->push_back(Expression::make_func_reference(no, NULL, bloc));
-
- ++p;
- go_assert(p == fields->end());
-
- return Expression::make_struct_composite_literal(method_type, vals, bloc);
-}
-
-// Return a composite literal for the type descriptor of a plain type.
-// RUNTIME_TYPE_KIND is the value of the kind field. If NAME is not
-// NULL, it is the name to use as well as the list of methods.
-
-Expression*
-Type::plain_type_descriptor(Gogo* gogo, int runtime_type_kind,
- Named_type* name)
-{
- return this->type_descriptor_constructor(gogo, runtime_type_kind,
- name, NULL, true);
-}
-
-// Return the type reflection string for this type.
-
-std::string
-Type::reflection(Gogo* gogo) const
-{
- std::string ret;
-
- // The do_reflection virtual function should set RET to the
- // reflection string.
- this->do_reflection(gogo, &ret);
-
- return ret;
-}
-
-// Return a mangled name for the type.
-
-std::string
-Type::mangled_name(Gogo* gogo) const
-{
- std::string ret;
-
- // The do_mangled_name virtual function should set RET to the
- // mangled name. For a composite type it should append a code for
- // the composition and then call do_mangled_name on the components.
- this->do_mangled_name(gogo, &ret);
-
- return ret;
-}
-
-// Return whether the backend size of the type is known.
-
-bool
-Type::is_backend_type_size_known(Gogo* gogo)
-{
- switch (this->classification_)
- {
- case TYPE_ERROR:
- case TYPE_VOID:
- case TYPE_BOOLEAN:
- case TYPE_INTEGER:
- case TYPE_FLOAT:
- case TYPE_COMPLEX:
- case TYPE_STRING:
- case TYPE_FUNCTION:
- case TYPE_POINTER:
- case TYPE_NIL:
- case TYPE_MAP:
- case TYPE_CHANNEL:
- case TYPE_INTERFACE:
- return true;
-
- case TYPE_STRUCT:
- {
- const Struct_field_list* fields = this->struct_type()->fields();
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf)
- if (!pf->type()->is_backend_type_size_known(gogo))
- return false;
- return true;
- }
-
- case TYPE_ARRAY:
- {
- const Array_type* at = this->array_type();
- if (at->length() == NULL)
- return true;
- else
- {
- Numeric_constant nc;
- if (!at->length()->numeric_constant_value(&nc))
- return false;
- mpz_t ival;
- if (!nc.to_int(&ival))
- return false;
- mpz_clear(ival);
- return at->element_type()->is_backend_type_size_known(gogo);
- }
- }
-
- case TYPE_NAMED:
- // Begin converting this type to the backend representation.
- // This will create a placeholder if necessary.
- this->get_backend(gogo);
- return this->named_type()->is_named_backend_type_size_known();
-
- case TYPE_FORWARD:
- {
- Forward_declaration_type* fdt = this->forward_declaration_type();
- return fdt->real_type()->is_backend_type_size_known(gogo);
- }
-
- case TYPE_SINK:
- case TYPE_CALL_MULTIPLE_RESULT:
- go_unreachable();
-
- default:
- go_unreachable();
- }
-}
-
-// If the size of the type can be determined, set *PSIZE to the size
-// in bytes and return true. Otherwise, return false. This queries
-// the backend.
-
-bool
-Type::backend_type_size(Gogo* gogo, unsigned int *psize)
-{
- if (!this->is_backend_type_size_known(gogo))
- return false;
- Btype* bt = this->get_backend_placeholder(gogo);
- size_t size = gogo->backend()->type_size(bt);
- *psize = static_cast<unsigned int>(size);
- if (*psize != size)
- return false;
- return true;
-}
-
-// If the alignment of the type can be determined, set *PALIGN to
-// the alignment in bytes and return true. Otherwise, return false.
-
-bool
-Type::backend_type_align(Gogo* gogo, unsigned int *palign)
-{
- if (!this->is_backend_type_size_known(gogo))
- return false;
- Btype* bt = this->get_backend_placeholder(gogo);
- size_t align = gogo->backend()->type_alignment(bt);
- *palign = static_cast<unsigned int>(align);
- if (*palign != align)
- return false;
- return true;
-}
-
-// Like backend_type_align, but return the alignment when used as a
-// field.
-
-bool
-Type::backend_type_field_align(Gogo* gogo, unsigned int *palign)
-{
- if (!this->is_backend_type_size_known(gogo))
- return false;
- Btype* bt = this->get_backend_placeholder(gogo);
- size_t a = gogo->backend()->type_field_alignment(bt);
- *palign = static_cast<unsigned int>(a);
- if (*palign != a)
- return false;
- return true;
-}
-
-// Default function to export a type.
-
-void
-Type::do_export(Export*) const
-{
- go_unreachable();
-}
-
-// Import a type.
-
-Type*
-Type::import_type(Import* imp)
-{
- if (imp->match_c_string("("))
- return Function_type::do_import(imp);
- else if (imp->match_c_string("*"))
- return Pointer_type::do_import(imp);
- else if (imp->match_c_string("struct "))
- return Struct_type::do_import(imp);
- else if (imp->match_c_string("["))
- return Array_type::do_import(imp);
- else if (imp->match_c_string("map "))
- return Map_type::do_import(imp);
- else if (imp->match_c_string("chan "))
- return Channel_type::do_import(imp);
- else if (imp->match_c_string("interface"))
- return Interface_type::do_import(imp);
- else
- {
- error_at(imp->location(), "import error: expected type");
- return Type::make_error_type();
- }
-}
-
-// A type used to indicate a parsing error. This exists to simplify
-// later error detection.
-
-class Error_type : public Type
-{
- public:
- Error_type()
- : Type(TYPE_ERROR)
- { }
-
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- Btype*
- do_get_backend(Gogo* gogo)
- { return gogo->backend()->error_type(); }
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*)
- { return Expression::make_error(Linemap::predeclared_location()); }
-
- void
- do_reflection(Gogo*, std::string*) const
- { go_assert(saw_errors()); }
-
- void
- do_mangled_name(Gogo*, std::string* ret) const
- { ret->push_back('E'); }
-};
-
-Type*
-Type::make_error_type()
-{
- static Error_type singleton_error_type;
- return &singleton_error_type;
-}
-
-// The void type.
-
-class Void_type : public Type
-{
- public:
- Void_type()
- : Type(TYPE_VOID)
- { }
-
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- Btype*
- do_get_backend(Gogo* gogo)
- { return gogo->backend()->void_type(); }
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*)
- { go_unreachable(); }
-
- void
- do_reflection(Gogo*, std::string*) const
- { }
-
- void
- do_mangled_name(Gogo*, std::string* ret) const
- { ret->push_back('v'); }
-};
-
-Type*
-Type::make_void_type()
-{
- static Void_type singleton_void_type;
- return &singleton_void_type;
-}
-
-// The boolean type.
-
-class Boolean_type : public Type
-{
- public:
- Boolean_type()
- : Type(TYPE_BOOLEAN)
- { }
-
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return true; }
-
- Btype*
- do_get_backend(Gogo* gogo)
- { return gogo->backend()->bool_type(); }
-
- Expression*
- do_type_descriptor(Gogo*, Named_type* name);
-
- // We should not be asked for the reflection string of a basic type.
- void
- do_reflection(Gogo*, std::string* ret) const
- { ret->append("bool"); }
-
- void
- do_mangled_name(Gogo*, std::string* ret) const
- { ret->push_back('b'); }
-};
-
-// Make the type descriptor.
-
-Expression*
-Boolean_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- if (name != NULL)
- return this->plain_type_descriptor(gogo, RUNTIME_TYPE_KIND_BOOL, name);
- else
- {
- Named_object* no = gogo->lookup_global("bool");
- go_assert(no != NULL);
- return Type::type_descriptor(gogo, no->type_value());
- }
-}
-
-Type*
-Type::make_boolean_type()
-{
- static Boolean_type boolean_type;
- return &boolean_type;
-}
-
-// The named type "bool".
-
-static Named_type* named_bool_type;
-
-// Get the named type "bool".
-
-Named_type*
-Type::lookup_bool_type()
-{
- return named_bool_type;
-}
-
-// Make the named type "bool".
-
-Named_type*
-Type::make_named_bool_type()
-{
- Type* bool_type = Type::make_boolean_type();
- Named_object* named_object =
- Named_object::make_type("bool", NULL, bool_type,
- Linemap::predeclared_location());
- Named_type* named_type = named_object->type_value();
- named_bool_type = named_type;
- return named_type;
-}
-
-// Class Integer_type.
-
-Integer_type::Named_integer_types Integer_type::named_integer_types;
-
-// Create a new integer type. Non-abstract integer types always have
-// names.
-
-Named_type*
-Integer_type::create_integer_type(const char* name, bool is_unsigned,
- int bits, int runtime_type_kind)
-{
- Integer_type* integer_type = new Integer_type(false, is_unsigned, bits,
- runtime_type_kind);
- std::string sname(name);
- Named_object* named_object =
- Named_object::make_type(sname, NULL, integer_type,
- Linemap::predeclared_location());
- Named_type* named_type = named_object->type_value();
- std::pair<Named_integer_types::iterator, bool> ins =
- Integer_type::named_integer_types.insert(std::make_pair(sname, named_type));
- go_assert(ins.second);
- return named_type;
-}
-
-// Look up an existing integer type.
-
-Named_type*
-Integer_type::lookup_integer_type(const char* name)
-{
- Named_integer_types::const_iterator p =
- Integer_type::named_integer_types.find(name);
- go_assert(p != Integer_type::named_integer_types.end());
- return p->second;
-}
-
-// Create a new abstract integer type.
-
-Integer_type*
-Integer_type::create_abstract_integer_type()
-{
- static Integer_type* abstract_type;
- if (abstract_type == NULL)
- {
- Type* int_type = Type::lookup_integer_type("int");
- abstract_type = new Integer_type(true, false,
- int_type->integer_type()->bits(),
- RUNTIME_TYPE_KIND_INT);
- }
- return abstract_type;
-}
-
-// Create a new abstract character type.
-
-Integer_type*
-Integer_type::create_abstract_character_type()
-{
- static Integer_type* abstract_type;
- if (abstract_type == NULL)
- {
- abstract_type = new Integer_type(true, false, 32,
- RUNTIME_TYPE_KIND_INT32);
- abstract_type->set_is_rune();
- }
- return abstract_type;
-}
-
-// Integer type compatibility.
-
-bool
-Integer_type::is_identical(const Integer_type* t) const
-{
- if (this->is_unsigned_ != t->is_unsigned_ || this->bits_ != t->bits_)
- return false;
- return this->is_abstract_ == t->is_abstract_;
-}
-
-// Hash code.
-
-unsigned int
-Integer_type::do_hash_for_method(Gogo*) const
-{
- return ((this->bits_ << 4)
- + ((this->is_unsigned_ ? 1 : 0) << 8)
- + ((this->is_abstract_ ? 1 : 0) << 9));
-}
-
-// Convert an Integer_type to the backend representation.
-
-Btype*
-Integer_type::do_get_backend(Gogo* gogo)
-{
- if (this->is_abstract_)
- {
- go_assert(saw_errors());
- return gogo->backend()->error_type();
- }
- return gogo->backend()->integer_type(this->is_unsigned_, this->bits_);
-}
-
-// The type descriptor for an integer type. Integer types are always
-// named.
-
-Expression*
-Integer_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- go_assert(name != NULL || saw_errors());
- return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name);
-}
-
-// We should not be asked for the reflection string of a basic type.
-
-void
-Integer_type::do_reflection(Gogo*, std::string*) const
-{
- go_assert(saw_errors());
-}
-
-// Mangled name.
-
-void
-Integer_type::do_mangled_name(Gogo*, std::string* ret) const
-{
- char buf[100];
- snprintf(buf, sizeof buf, "i%s%s%de",
- this->is_abstract_ ? "a" : "",
- this->is_unsigned_ ? "u" : "",
- this->bits_);
- ret->append(buf);
-}
-
-// Make an integer type.
-
-Named_type*
-Type::make_integer_type(const char* name, bool is_unsigned, int bits,
- int runtime_type_kind)
-{
- return Integer_type::create_integer_type(name, is_unsigned, bits,
- runtime_type_kind);
-}
-
-// Make an abstract integer type.
-
-Integer_type*
-Type::make_abstract_integer_type()
-{
- return Integer_type::create_abstract_integer_type();
-}
-
-// Make an abstract character type.
-
-Integer_type*
-Type::make_abstract_character_type()
-{
- return Integer_type::create_abstract_character_type();
-}
-
-// Look up an integer type.
-
-Named_type*
-Type::lookup_integer_type(const char* name)
-{
- return Integer_type::lookup_integer_type(name);
-}
-
-// Class Float_type.
-
-Float_type::Named_float_types Float_type::named_float_types;
-
-// Create a new float type. Non-abstract float types always have
-// names.
-
-Named_type*
-Float_type::create_float_type(const char* name, int bits,
- int runtime_type_kind)
-{
- Float_type* float_type = new Float_type(false, bits, runtime_type_kind);
- std::string sname(name);
- Named_object* named_object =
- Named_object::make_type(sname, NULL, float_type,
- Linemap::predeclared_location());
- Named_type* named_type = named_object->type_value();
- std::pair<Named_float_types::iterator, bool> ins =
- Float_type::named_float_types.insert(std::make_pair(sname, named_type));
- go_assert(ins.second);
- return named_type;
-}
-
-// Look up an existing float type.
-
-Named_type*
-Float_type::lookup_float_type(const char* name)
-{
- Named_float_types::const_iterator p =
- Float_type::named_float_types.find(name);
- go_assert(p != Float_type::named_float_types.end());
- return p->second;
-}
-
-// Create a new abstract float type.
-
-Float_type*
-Float_type::create_abstract_float_type()
-{
- static Float_type* abstract_type;
- if (abstract_type == NULL)
- abstract_type = new Float_type(true, 64, RUNTIME_TYPE_KIND_FLOAT64);
- return abstract_type;
-}
-
-// Whether this type is identical with T.
-
-bool
-Float_type::is_identical(const Float_type* t) const
-{
- if (this->bits_ != t->bits_)
- return false;
- return this->is_abstract_ == t->is_abstract_;
-}
-
-// Hash code.
-
-unsigned int
-Float_type::do_hash_for_method(Gogo*) const
-{
- return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8);
-}
-
-// Convert to the backend representation.
-
-Btype*
-Float_type::do_get_backend(Gogo* gogo)
-{
- return gogo->backend()->float_type(this->bits_);
-}
-
-// The type descriptor for a float type. Float types are always named.
-
-Expression*
-Float_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- go_assert(name != NULL || saw_errors());
- return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name);
-}
-
-// We should not be asked for the reflection string of a basic type.
-
-void
-Float_type::do_reflection(Gogo*, std::string*) const
-{
- go_assert(saw_errors());
-}
-
-// Mangled name.
-
-void
-Float_type::do_mangled_name(Gogo*, std::string* ret) const
-{
- char buf[100];
- snprintf(buf, sizeof buf, "f%s%de",
- this->is_abstract_ ? "a" : "",
- this->bits_);
- ret->append(buf);
-}
-
-// Make a floating point type.
-
-Named_type*
-Type::make_float_type(const char* name, int bits, int runtime_type_kind)
-{
- return Float_type::create_float_type(name, bits, runtime_type_kind);
-}
-
-// Make an abstract float type.
-
-Float_type*
-Type::make_abstract_float_type()
-{
- return Float_type::create_abstract_float_type();
-}
-
-// Look up a float type.
-
-Named_type*
-Type::lookup_float_type(const char* name)
-{
- return Float_type::lookup_float_type(name);
-}
-
-// Class Complex_type.
-
-Complex_type::Named_complex_types Complex_type::named_complex_types;
-
-// Create a new complex type. Non-abstract complex types always have
-// names.
-
-Named_type*
-Complex_type::create_complex_type(const char* name, int bits,
- int runtime_type_kind)
-{
- Complex_type* complex_type = new Complex_type(false, bits,
- runtime_type_kind);
- std::string sname(name);
- Named_object* named_object =
- Named_object::make_type(sname, NULL, complex_type,
- Linemap::predeclared_location());
- Named_type* named_type = named_object->type_value();
- std::pair<Named_complex_types::iterator, bool> ins =
- Complex_type::named_complex_types.insert(std::make_pair(sname,
- named_type));
- go_assert(ins.second);
- return named_type;
-}
-
-// Look up an existing complex type.
-
-Named_type*
-Complex_type::lookup_complex_type(const char* name)
-{
- Named_complex_types::const_iterator p =
- Complex_type::named_complex_types.find(name);
- go_assert(p != Complex_type::named_complex_types.end());
- return p->second;
-}
-
-// Create a new abstract complex type.
-
-Complex_type*
-Complex_type::create_abstract_complex_type()
-{
- static Complex_type* abstract_type;
- if (abstract_type == NULL)
- abstract_type = new Complex_type(true, 128, RUNTIME_TYPE_KIND_COMPLEX128);
- return abstract_type;
-}
-
-// Whether this type is identical with T.
-
-bool
-Complex_type::is_identical(const Complex_type *t) const
-{
- if (this->bits_ != t->bits_)
- return false;
- return this->is_abstract_ == t->is_abstract_;
-}
-
-// Hash code.
-
-unsigned int
-Complex_type::do_hash_for_method(Gogo*) const
-{
- return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8);
-}
-
-// Convert to the backend representation.
-
-Btype*
-Complex_type::do_get_backend(Gogo* gogo)
-{
- return gogo->backend()->complex_type(this->bits_);
-}
-
-// The type descriptor for a complex type. Complex types are always
-// named.
-
-Expression*
-Complex_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- go_assert(name != NULL || saw_errors());
- return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name);
-}
-
-// We should not be asked for the reflection string of a basic type.
-
-void
-Complex_type::do_reflection(Gogo*, std::string*) const
-{
- go_assert(saw_errors());
-}
-
-// Mangled name.
-
-void
-Complex_type::do_mangled_name(Gogo*, std::string* ret) const
-{
- char buf[100];
- snprintf(buf, sizeof buf, "c%s%de",
- this->is_abstract_ ? "a" : "",
- this->bits_);
- ret->append(buf);
-}
-
-// Make a complex type.
-
-Named_type*
-Type::make_complex_type(const char* name, int bits, int runtime_type_kind)
-{
- return Complex_type::create_complex_type(name, bits, runtime_type_kind);
-}
-
-// Make an abstract complex type.
-
-Complex_type*
-Type::make_abstract_complex_type()
-{
- return Complex_type::create_abstract_complex_type();
-}
-
-// Look up a complex type.
-
-Named_type*
-Type::lookup_complex_type(const char* name)
-{
- return Complex_type::lookup_complex_type(name);
-}
-
-// Class String_type.
-
-// Convert String_type to the backend representation. A string is a
-// struct with two fields: a pointer to the characters and a length.
-
-Btype*
-String_type::do_get_backend(Gogo* gogo)
-{
- static Btype* backend_string_type;
- if (backend_string_type == NULL)
- {
- std::vector<Backend::Btyped_identifier> fields(2);
-
- Type* b = gogo->lookup_global("byte")->type_value();
- Type* pb = Type::make_pointer_type(b);
-
- // We aren't going to get back to this field to finish the
- // backend representation, so force it to be finished now.
- if (!gogo->named_types_are_converted())
- {
- Btype* bt = pb->get_backend_placeholder(gogo);
- pb->finish_backend(gogo, bt);
- }
-
- fields[0].name = "__data";
- fields[0].btype = pb->get_backend(gogo);
- fields[0].location = Linemap::predeclared_location();
-
- Type* int_type = Type::lookup_integer_type("int");
- fields[1].name = "__length";
- fields[1].btype = int_type->get_backend(gogo);
- fields[1].location = fields[0].location;
-
- backend_string_type = gogo->backend()->struct_type(fields);
- }
- return backend_string_type;
-}
-
-// Return a tree for the length of STRING.
-
-tree
-String_type::length_tree(Gogo*, tree string)
-{
- tree string_type = TREE_TYPE(string);
- go_assert(TREE_CODE(string_type) == RECORD_TYPE);
- tree length_field = DECL_CHAIN(TYPE_FIELDS(string_type));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(length_field)),
- "__length") == 0);
- return fold_build3(COMPONENT_REF, TREE_TYPE(length_field), string,
- length_field, NULL_TREE);
-}
-
-// Return a tree for a pointer to the bytes of STRING.
-
-tree
-String_type::bytes_tree(Gogo*, tree string)
-{
- tree string_type = TREE_TYPE(string);
- go_assert(TREE_CODE(string_type) == RECORD_TYPE);
- tree bytes_field = TYPE_FIELDS(string_type);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(bytes_field)),
- "__data") == 0);
- return fold_build3(COMPONENT_REF, TREE_TYPE(bytes_field), string,
- bytes_field, NULL_TREE);
-}
-
-// The type descriptor for the string type.
-
-Expression*
-String_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- if (name != NULL)
- return this->plain_type_descriptor(gogo, RUNTIME_TYPE_KIND_STRING, name);
- else
- {
- Named_object* no = gogo->lookup_global("string");
- go_assert(no != NULL);
- return Type::type_descriptor(gogo, no->type_value());
- }
-}
-
-// We should not be asked for the reflection string of a basic type.
-
-void
-String_type::do_reflection(Gogo*, std::string* ret) const
-{
- ret->append("string");
-}
-
-// Mangled name of a string type.
-
-void
-String_type::do_mangled_name(Gogo*, std::string* ret) const
-{
- ret->push_back('z');
-}
-
-// Make a string type.
-
-Type*
-Type::make_string_type()
-{
- static String_type string_type;
- return &string_type;
-}
-
-// The named type "string".
-
-static Named_type* named_string_type;
-
-// Get the named type "string".
-
-Named_type*
-Type::lookup_string_type()
-{
- return named_string_type;
-}
-
-// Make the named type string.
-
-Named_type*
-Type::make_named_string_type()
-{
- Type* string_type = Type::make_string_type();
- Named_object* named_object =
- Named_object::make_type("string", NULL, string_type,
- Linemap::predeclared_location());
- Named_type* named_type = named_object->type_value();
- named_string_type = named_type;
- return named_type;
-}
-
-// The sink type. This is the type of the blank identifier _. Any
-// type may be assigned to it.
-
-class Sink_type : public Type
-{
- public:
- Sink_type()
- : Type(TYPE_SINK)
- { }
-
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- Btype*
- do_get_backend(Gogo*)
- { go_unreachable(); }
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*)
- { go_unreachable(); }
-
- void
- do_reflection(Gogo*, std::string*) const
- { go_unreachable(); }
-
- void
- do_mangled_name(Gogo*, std::string*) const
- { go_unreachable(); }
-};
-
-// Make the sink type.
-
-Type*
-Type::make_sink_type()
-{
- static Sink_type sink_type;
- return &sink_type;
-}
-
-// Class Function_type.
-
-// Traversal.
-
-int
-Function_type::do_traverse(Traverse* traverse)
-{
- if (this->receiver_ != NULL
- && Type::traverse(this->receiver_->type(), traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (this->parameters_ != NULL
- && this->parameters_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (this->results_ != NULL
- && this->results_->traverse(traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Returns whether T is a valid redeclaration of this type. If this
-// returns false, and REASON is not NULL, *REASON may be set to a
-// brief explanation of why it returned false.
-
-bool
-Function_type::is_valid_redeclaration(const Function_type* t,
- std::string* reason) const
-{
- if (!this->is_identical(t, false, true, reason))
- return false;
-
- // A redeclaration of a function is required to use the same names
- // for the receiver and parameters.
- if (this->receiver() != NULL
- && this->receiver()->name() != t->receiver()->name())
- {
- if (reason != NULL)
- *reason = "receiver name changed";
- return false;
- }
-
- const Typed_identifier_list* parms1 = this->parameters();
- const Typed_identifier_list* parms2 = t->parameters();
- if (parms1 != NULL)
- {
- Typed_identifier_list::const_iterator p1 = parms1->begin();
- for (Typed_identifier_list::const_iterator p2 = parms2->begin();
- p2 != parms2->end();
- ++p2, ++p1)
- {
- if (p1->name() != p2->name())
- {
- if (reason != NULL)
- *reason = "parameter name changed";
- return false;
- }
-
- // This is called at parse time, so we may have unknown
- // types.
- Type* t1 = p1->type()->forwarded();
- Type* t2 = p2->type()->forwarded();
- if (t1 != t2
- && t1->forward_declaration_type() != NULL
- && (t2->forward_declaration_type() == NULL
- || (t1->forward_declaration_type()->named_object()
- != t2->forward_declaration_type()->named_object())))
- return false;
- }
- }
-
- const Typed_identifier_list* results1 = this->results();
- const Typed_identifier_list* results2 = t->results();
- if (results1 != NULL)
- {
- Typed_identifier_list::const_iterator res1 = results1->begin();
- for (Typed_identifier_list::const_iterator res2 = results2->begin();
- res2 != results2->end();
- ++res2, ++res1)
- {
- if (res1->name() != res2->name())
- {
- if (reason != NULL)
- *reason = "result name changed";
- return false;
- }
-
- // This is called at parse time, so we may have unknown
- // types.
- Type* t1 = res1->type()->forwarded();
- Type* t2 = res2->type()->forwarded();
- if (t1 != t2
- && t1->forward_declaration_type() != NULL
- && (t2->forward_declaration_type() == NULL
- || (t1->forward_declaration_type()->named_object()
- != t2->forward_declaration_type()->named_object())))
- return false;
- }
- }
-
- return true;
-}
-
-// Check whether T is the same as this type.
-
-bool
-Function_type::is_identical(const Function_type* t, bool ignore_receiver,
- bool errors_are_identical,
- std::string* reason) const
-{
- if (!ignore_receiver)
- {
- const Typed_identifier* r1 = this->receiver();
- const Typed_identifier* r2 = t->receiver();
- if ((r1 != NULL) != (r2 != NULL))
- {
- if (reason != NULL)
- *reason = _("different receiver types");
- return false;
- }
- if (r1 != NULL)
- {
- if (!Type::are_identical(r1->type(), r2->type(), errors_are_identical,
- reason))
- {
- if (reason != NULL && !reason->empty())
- *reason = "receiver: " + *reason;
- return false;
- }
- }
- }
-
- const Typed_identifier_list* parms1 = this->parameters();
- const Typed_identifier_list* parms2 = t->parameters();
- if ((parms1 != NULL) != (parms2 != NULL))
- {
- if (reason != NULL)
- *reason = _("different number of parameters");
- return false;
- }
- if (parms1 != NULL)
- {
- Typed_identifier_list::const_iterator p1 = parms1->begin();
- for (Typed_identifier_list::const_iterator p2 = parms2->begin();
- p2 != parms2->end();
- ++p2, ++p1)
- {
- if (p1 == parms1->end())
- {
- if (reason != NULL)
- *reason = _("different number of parameters");
- return false;
- }
-
- if (!Type::are_identical(p1->type(), p2->type(),
- errors_are_identical, NULL))
- {
- if (reason != NULL)
- *reason = _("different parameter types");
- return false;
- }
- }
- if (p1 != parms1->end())
- {
- if (reason != NULL)
- *reason = _("different number of parameters");
- return false;
- }
- }
-
- if (this->is_varargs() != t->is_varargs())
- {
- if (reason != NULL)
- *reason = _("different varargs");
- return false;
- }
-
- const Typed_identifier_list* results1 = this->results();
- const Typed_identifier_list* results2 = t->results();
- if ((results1 != NULL) != (results2 != NULL))
- {
- if (reason != NULL)
- *reason = _("different number of results");
- return false;
- }
- if (results1 != NULL)
- {
- Typed_identifier_list::const_iterator res1 = results1->begin();
- for (Typed_identifier_list::const_iterator res2 = results2->begin();
- res2 != results2->end();
- ++res2, ++res1)
- {
- if (res1 == results1->end())
- {
- if (reason != NULL)
- *reason = _("different number of results");
- return false;
- }
-
- if (!Type::are_identical(res1->type(), res2->type(),
- errors_are_identical, NULL))
- {
- if (reason != NULL)
- *reason = _("different result types");
- return false;
- }
- }
- if (res1 != results1->end())
- {
- if (reason != NULL)
- *reason = _("different number of results");
- return false;
- }
- }
-
- return true;
-}
-
-// Hash code.
-
-unsigned int
-Function_type::do_hash_for_method(Gogo* gogo) const
-{
- unsigned int ret = 0;
- // We ignore the receiver type for hash codes, because we need to
- // get the same hash code for a method in an interface and a method
- // declared for a type. The former will not have a receiver.
- if (this->parameters_ != NULL)
- {
- int shift = 1;
- for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
- p != this->parameters_->end();
- ++p, ++shift)
- ret += p->type()->hash_for_method(gogo) << shift;
- }
- if (this->results_ != NULL)
- {
- int shift = 2;
- for (Typed_identifier_list::const_iterator p = this->results_->begin();
- p != this->results_->end();
- ++p, ++shift)
- ret += p->type()->hash_for_method(gogo) << shift;
- }
- if (this->is_varargs_)
- ret += 1;
- ret <<= 4;
- return ret;
-}
-
-// Get the backend representation for a function type.
-
-Btype*
-Function_type::do_get_backend(Gogo* gogo)
-{
- Backend::Btyped_identifier breceiver;
- if (this->receiver_ != NULL)
- {
- breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name());
-
- // We always pass the address of the receiver parameter, in
- // order to make interface calls work with unknown types.
- Type* rtype = this->receiver_->type();
- if (rtype->points_to() == NULL)
- rtype = Type::make_pointer_type(rtype);
- breceiver.btype = rtype->get_backend(gogo);
- breceiver.location = this->receiver_->location();
- }
-
- std::vector<Backend::Btyped_identifier> bparameters;
- if (this->parameters_ != NULL)
- {
- bparameters.resize(this->parameters_->size());
- size_t i = 0;
- for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
- p != this->parameters_->end();
- ++p, ++i)
- {
- bparameters[i].name = Gogo::unpack_hidden_name(p->name());
- bparameters[i].btype = p->type()->get_backend(gogo);
- bparameters[i].location = p->location();
- }
- go_assert(i == bparameters.size());
- }
-
- std::vector<Backend::Btyped_identifier> bresults;
- if (this->results_ != NULL)
- {
- bresults.resize(this->results_->size());
- size_t i = 0;
- for (Typed_identifier_list::const_iterator p = this->results_->begin();
- p != this->results_->end();
- ++p, ++i)
- {
- bresults[i].name = Gogo::unpack_hidden_name(p->name());
- bresults[i].btype = p->type()->get_backend(gogo);
- bresults[i].location = p->location();
- }
- go_assert(i == bresults.size());
- }
-
- return gogo->backend()->function_type(breceiver, bparameters, bresults,
- this->location());
-}
-
-// The type of a function type descriptor.
-
-Type*
-Function_type::make_function_type_descriptor_type()
-{
- static Type* ret;
- if (ret == NULL)
- {
- Type* tdt = Type::make_type_descriptor_type();
- Type* ptdt = Type::make_type_descriptor_ptr_type();
-
- Type* bool_type = Type::lookup_bool_type();
-
- Type* slice_type = Type::make_array_type(ptdt, NULL);
-
- Struct_type* s = Type::make_builtin_struct_type(4,
- "", tdt,
- "dotdotdot", bool_type,
- "in", slice_type,
- "out", slice_type);
-
- ret = Type::make_builtin_named_type("FuncType", s);
- }
-
- return ret;
-}
-
-// The type descriptor for a function type.
-
-Expression*
-Function_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- Location bloc = Linemap::predeclared_location();
-
- Type* ftdt = Function_type::make_function_type_descriptor_type();
-
- const Struct_field_list* fields = ftdt->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(4);
-
- Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("commonType"));
- vals->push_back(this->type_descriptor_constructor(gogo,
- RUNTIME_TYPE_KIND_FUNC,
- name, NULL, true));
-
- ++p;
- go_assert(p->is_field_name("dotdotdot"));
- vals->push_back(Expression::make_boolean(this->is_varargs(), bloc));
-
- ++p;
- go_assert(p->is_field_name("in"));
- vals->push_back(this->type_descriptor_params(p->type(), this->receiver(),
- this->parameters()));
-
- ++p;
- go_assert(p->is_field_name("out"));
- vals->push_back(this->type_descriptor_params(p->type(), NULL,
- this->results()));
-
- ++p;
- go_assert(p == fields->end());
-
- return Expression::make_struct_composite_literal(ftdt, vals, bloc);
-}
-
-// Return a composite literal for the parameters or results of a type
-// descriptor.
-
-Expression*
-Function_type::type_descriptor_params(Type* params_type,
- const Typed_identifier* receiver,
- const Typed_identifier_list* params)
-{
- Location bloc = Linemap::predeclared_location();
-
- if (receiver == NULL && params == NULL)
- return Expression::make_slice_composite_literal(params_type, NULL, bloc);
-
- Expression_list* vals = new Expression_list();
- vals->reserve((params == NULL ? 0 : params->size())
- + (receiver != NULL ? 1 : 0));
-
- if (receiver != NULL)
- vals->push_back(Expression::make_type_descriptor(receiver->type(), bloc));
-
- if (params != NULL)
- {
- for (Typed_identifier_list::const_iterator p = params->begin();
- p != params->end();
- ++p)
- vals->push_back(Expression::make_type_descriptor(p->type(), bloc));
- }
-
- return Expression::make_slice_composite_literal(params_type, vals, bloc);
-}
-
-// The reflection string.
-
-void
-Function_type::do_reflection(Gogo* gogo, std::string* ret) const
-{
- // FIXME: Turn this off until we straighten out the type of the
- // struct field used in a go statement which calls a method.
- // go_assert(this->receiver_ == NULL);
-
- ret->append("func");
-
- if (this->receiver_ != NULL)
- {
- ret->push_back('(');
- this->append_reflection(this->receiver_->type(), gogo, ret);
- ret->push_back(')');
- }
-
- ret->push_back('(');
- const Typed_identifier_list* params = this->parameters();
- if (params != NULL)
- {
- bool is_varargs = this->is_varargs_;
- for (Typed_identifier_list::const_iterator p = params->begin();
- p != params->end();
- ++p)
- {
- if (p != params->begin())
- ret->append(", ");
- if (!is_varargs || p + 1 != params->end())
- this->append_reflection(p->type(), gogo, ret);
- else
- {
- ret->append("...");
- this->append_reflection(p->type()->array_type()->element_type(),
- gogo, ret);
- }
- }
- }
- ret->push_back(')');
-
- const Typed_identifier_list* results = this->results();
- if (results != NULL && !results->empty())
- {
- if (results->size() == 1)
- ret->push_back(' ');
- else
- ret->append(" (");
- for (Typed_identifier_list::const_iterator p = results->begin();
- p != results->end();
- ++p)
- {
- if (p != results->begin())
- ret->append(", ");
- this->append_reflection(p->type(), gogo, ret);
- }
- if (results->size() > 1)
- ret->push_back(')');
- }
-}
-
-// Mangled name.
-
-void
-Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('F');
-
- if (this->receiver_ != NULL)
- {
- ret->push_back('m');
- this->append_mangled_name(this->receiver_->type(), gogo, ret);
- }
-
- const Typed_identifier_list* params = this->parameters();
- if (params != NULL)
- {
- ret->push_back('p');
- for (Typed_identifier_list::const_iterator p = params->begin();
- p != params->end();
- ++p)
- this->append_mangled_name(p->type(), gogo, ret);
- if (this->is_varargs_)
- ret->push_back('V');
- ret->push_back('e');
- }
-
- const Typed_identifier_list* results = this->results();
- if (results != NULL)
- {
- ret->push_back('r');
- for (Typed_identifier_list::const_iterator p = results->begin();
- p != results->end();
- ++p)
- this->append_mangled_name(p->type(), gogo, ret);
- ret->push_back('e');
- }
-
- ret->push_back('e');
-}
-
-// Export a function type.
-
-void
-Function_type::do_export(Export* exp) const
-{
- // We don't write out the receiver. The only function types which
- // should have a receiver are the ones associated with explicitly
- // defined methods. For those the receiver type is written out by
- // Function::export_func.
-
- exp->write_c_string("(");
- bool first = true;
- if (this->parameters_ != NULL)
- {
- bool is_varargs = this->is_varargs_;
- for (Typed_identifier_list::const_iterator p =
- this->parameters_->begin();
- p != this->parameters_->end();
- ++p)
- {
- if (first)
- first = false;
- else
- exp->write_c_string(", ");
- exp->write_name(p->name());
- exp->write_c_string(" ");
- if (!is_varargs || p + 1 != this->parameters_->end())
- exp->write_type(p->type());
- else
- {
- exp->write_c_string("...");
- exp->write_type(p->type()->array_type()->element_type());
- }
- }
- }
- exp->write_c_string(")");
-
- const Typed_identifier_list* results = this->results_;
- if (results != NULL)
- {
- exp->write_c_string(" ");
- if (results->size() == 1 && results->begin()->name().empty())
- exp->write_type(results->begin()->type());
- else
- {
- first = true;
- exp->write_c_string("(");
- for (Typed_identifier_list::const_iterator p = results->begin();
- p != results->end();
- ++p)
- {
- if (first)
- first = false;
- else
- exp->write_c_string(", ");
- exp->write_name(p->name());
- exp->write_c_string(" ");
- exp->write_type(p->type());
- }
- exp->write_c_string(")");
- }
- }
-}
-
-// Import a function type.
-
-Function_type*
-Function_type::do_import(Import* imp)
-{
- imp->require_c_string("(");
- Typed_identifier_list* parameters;
- bool is_varargs = false;
- if (imp->peek_char() == ')')
- parameters = NULL;
- else
- {
- parameters = new Typed_identifier_list();
- while (true)
- {
- std::string name = imp->read_name();
- imp->require_c_string(" ");
-
- if (imp->match_c_string("..."))
- {
- imp->advance(3);
- is_varargs = true;
- }
-
- Type* ptype = imp->read_type();
- if (is_varargs)
- ptype = Type::make_array_type(ptype, NULL);
- parameters->push_back(Typed_identifier(name, ptype,
- imp->location()));
- if (imp->peek_char() != ',')
- break;
- go_assert(!is_varargs);
- imp->require_c_string(", ");
- }
- }
- imp->require_c_string(")");
-
- Typed_identifier_list* results;
- if (imp->peek_char() != ' ')
- results = NULL;
- else
- {
- imp->advance(1);
- results = new Typed_identifier_list;
- if (imp->peek_char() != '(')
- {
- Type* rtype = imp->read_type();
- results->push_back(Typed_identifier("", rtype, imp->location()));
- }
- else
- {
- imp->advance(1);
- while (true)
- {
- std::string name = imp->read_name();
- imp->require_c_string(" ");
- Type* rtype = imp->read_type();
- results->push_back(Typed_identifier(name, rtype,
- imp->location()));
- if (imp->peek_char() != ',')
- break;
- imp->require_c_string(", ");
- }
- imp->require_c_string(")");
- }
- }
-
- Function_type* ret = Type::make_function_type(NULL, parameters, results,
- imp->location());
- if (is_varargs)
- ret->set_is_varargs();
- return ret;
-}
-
-// Make a copy of a function type without a receiver.
-
-Function_type*
-Function_type::copy_without_receiver() const
-{
- go_assert(this->is_method());
- Function_type *ret = Type::make_function_type(NULL, this->parameters_,
- this->results_,
- this->location_);
- if (this->is_varargs())
- ret->set_is_varargs();
- if (this->is_builtin())
- ret->set_is_builtin();
- return ret;
-}
-
-// Make a copy of a function type with a receiver.
-
-Function_type*
-Function_type::copy_with_receiver(Type* receiver_type) const
-{
- go_assert(!this->is_method());
- Typed_identifier* receiver = new Typed_identifier("", receiver_type,
- this->location_);
- Function_type* ret = Type::make_function_type(receiver, this->parameters_,
- this->results_,
- this->location_);
- if (this->is_varargs_)
- ret->set_is_varargs();
- return ret;
-}
-
-// Make a function type.
-
-Function_type*
-Type::make_function_type(Typed_identifier* receiver,
- Typed_identifier_list* parameters,
- Typed_identifier_list* results,
- Location location)
-{
- return new Function_type(receiver, parameters, results, location);
-}
-
-// Class Pointer_type.
-
-// Traversal.
-
-int
-Pointer_type::do_traverse(Traverse* traverse)
-{
- return Type::traverse(this->to_type_, traverse);
-}
-
-// Hash code.
-
-unsigned int
-Pointer_type::do_hash_for_method(Gogo* gogo) const
-{
- return this->to_type_->hash_for_method(gogo) << 4;
-}
-
-// Get the backend representation for a pointer type.
-
-Btype*
-Pointer_type::do_get_backend(Gogo* gogo)
-{
- Btype* to_btype = this->to_type_->get_backend(gogo);
- return gogo->backend()->pointer_type(to_btype);
-}
-
-// The type of a pointer type descriptor.
-
-Type*
-Pointer_type::make_pointer_type_descriptor_type()
-{
- static Type* ret;
- if (ret == NULL)
- {
- Type* tdt = Type::make_type_descriptor_type();
- Type* ptdt = Type::make_type_descriptor_ptr_type();
-
- Struct_type* s = Type::make_builtin_struct_type(2,
- "", tdt,
- "elem", ptdt);
-
- ret = Type::make_builtin_named_type("PtrType", s);
- }
-
- return ret;
-}
-
-// The type descriptor for a pointer type.
-
-Expression*
-Pointer_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- if (this->is_unsafe_pointer_type())
- {
- go_assert(name != NULL);
- return this->plain_type_descriptor(gogo,
- RUNTIME_TYPE_KIND_UNSAFE_POINTER,
- name);
- }
- else
- {
- Location bloc = Linemap::predeclared_location();
-
- const Methods* methods;
- Type* deref = this->points_to();
- if (deref->named_type() != NULL)
- methods = deref->named_type()->methods();
- else if (deref->struct_type() != NULL)
- methods = deref->struct_type()->methods();
- else
- methods = NULL;
-
- Type* ptr_tdt = Pointer_type::make_pointer_type_descriptor_type();
-
- const Struct_field_list* fields = ptr_tdt->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(2);
-
- Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("commonType"));
- vals->push_back(this->type_descriptor_constructor(gogo,
- RUNTIME_TYPE_KIND_PTR,
- name, methods, false));
-
- ++p;
- go_assert(p->is_field_name("elem"));
- vals->push_back(Expression::make_type_descriptor(deref, bloc));
-
- return Expression::make_struct_composite_literal(ptr_tdt, vals, bloc);
- }
-}
-
-// Reflection string.
-
-void
-Pointer_type::do_reflection(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('*');
- this->append_reflection(this->to_type_, gogo, ret);
-}
-
-// Mangled name.
-
-void
-Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('p');
- this->append_mangled_name(this->to_type_, gogo, ret);
-}
-
-// Export.
-
-void
-Pointer_type::do_export(Export* exp) const
-{
- exp->write_c_string("*");
- if (this->is_unsafe_pointer_type())
- exp->write_c_string("any");
- else
- exp->write_type(this->to_type_);
-}
-
-// Import.
-
-Pointer_type*
-Pointer_type::do_import(Import* imp)
-{
- imp->require_c_string("*");
- if (imp->match_c_string("any"))
- {
- imp->advance(3);
- return Type::make_pointer_type(Type::make_void_type());
- }
- Type* to = imp->read_type();
- return Type::make_pointer_type(to);
-}
-
-// Make a pointer type.
-
-Pointer_type*
-Type::make_pointer_type(Type* to_type)
-{
- typedef Unordered_map(Type*, Pointer_type*) Hashtable;
- static Hashtable pointer_types;
- Hashtable::const_iterator p = pointer_types.find(to_type);
- if (p != pointer_types.end())
- return p->second;
- Pointer_type* ret = new Pointer_type(to_type);
- pointer_types[to_type] = ret;
- return ret;
-}
-
-// The nil type. We use a special type for nil because it is not the
-// same as any other type. In C term nil has type void*, but there is
-// no such type in Go.
-
-class Nil_type : public Type
-{
- public:
- Nil_type()
- : Type(TYPE_NIL)
- { }
-
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- Btype*
- do_get_backend(Gogo* gogo)
- { return gogo->backend()->pointer_type(gogo->backend()->void_type()); }
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*)
- { go_unreachable(); }
-
- void
- do_reflection(Gogo*, std::string*) const
- { go_unreachable(); }
-
- void
- do_mangled_name(Gogo*, std::string* ret) const
- { ret->push_back('n'); }
-};
-
-// Make the nil type.
-
-Type*
-Type::make_nil_type()
-{
- static Nil_type singleton_nil_type;
- return &singleton_nil_type;
-}
-
-// The type of a function call which returns multiple values. This is
-// really a struct, but we don't want to confuse a function call which
-// returns a struct with a function call which returns multiple
-// values.
-
-class Call_multiple_result_type : public Type
-{
- public:
- Call_multiple_result_type(Call_expression* call)
- : Type(TYPE_CALL_MULTIPLE_RESULT),
- call_(call)
- { }
-
- protected:
- bool
- do_has_pointer() const
- {
- go_assert(saw_errors());
- return false;
- }
-
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- Btype*
- do_get_backend(Gogo* gogo)
- {
- go_assert(saw_errors());
- return gogo->backend()->error_type();
- }
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*)
- {
- go_assert(saw_errors());
- return Expression::make_error(Linemap::unknown_location());
- }
-
- void
- do_reflection(Gogo*, std::string*) const
- { go_assert(saw_errors()); }
-
- void
- do_mangled_name(Gogo*, std::string*) const
- { go_assert(saw_errors()); }
-
- private:
- // The expression being called.
- Call_expression* call_;
-};
-
-// Make a call result type.
-
-Type*
-Type::make_call_multiple_result_type(Call_expression* call)
-{
- return new Call_multiple_result_type(call);
-}
-
-// Class Struct_field.
-
-// Get the name of a field.
-
-const std::string&
-Struct_field::field_name() const
-{
- const std::string& name(this->typed_identifier_.name());
- if (!name.empty())
- return name;
- else
- {
- // This is called during parsing, before anything is lowered, so
- // we have to be pretty careful to avoid dereferencing an
- // unknown type name.
- Type* t = this->typed_identifier_.type();
- Type* dt = t;
- if (t->classification() == Type::TYPE_POINTER)
- {
- // Very ugly.
- Pointer_type* ptype = static_cast<Pointer_type*>(t);
- dt = ptype->points_to();
- }
- if (dt->forward_declaration_type() != NULL)
- return dt->forward_declaration_type()->name();
- else if (dt->named_type() != NULL)
- return dt->named_type()->name();
- else if (t->is_error_type() || dt->is_error_type())
- {
- static const std::string error_string = "*error*";
- return error_string;
- }
- else
- {
- // Avoid crashing in the erroneous case where T is named but
- // DT is not.
- go_assert(t != dt);
- if (t->forward_declaration_type() != NULL)
- return t->forward_declaration_type()->name();
- else if (t->named_type() != NULL)
- return t->named_type()->name();
- else
- go_unreachable();
- }
- }
-}
-
-// Return whether this field is named NAME.
-
-bool
-Struct_field::is_field_name(const std::string& name) const
-{
- const std::string& me(this->typed_identifier_.name());
- if (!me.empty())
- return me == name;
- else
- {
- Type* t = this->typed_identifier_.type();
- if (t->points_to() != NULL)
- t = t->points_to();
- Named_type* nt = t->named_type();
- if (nt != NULL && nt->name() == name)
- return true;
-
- // This is a horrible hack caused by the fact that we don't pack
- // the names of builtin types. FIXME.
- if (nt != NULL
- && nt->is_builtin()
- && nt->name() == Gogo::unpack_hidden_name(name))
- return true;
-
- return false;
- }
-}
-
-// Class Struct_type.
-
-// A hash table used to find identical unnamed structs so that they
-// share method tables.
-
-Struct_type::Identical_structs Struct_type::identical_structs;
-
-// Traversal.
-
-int
-Struct_type::do_traverse(Traverse* traverse)
-{
- Struct_field_list* fields = this->fields_;
- if (fields != NULL)
- {
- for (Struct_field_list::iterator p = fields->begin();
- p != fields->end();
- ++p)
- {
- if (Type::traverse(p->type(), traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Verify that the struct type is complete and valid.
-
-bool
-Struct_type::do_verify()
-{
- Struct_field_list* fields = this->fields_;
- if (fields == NULL)
- return true;
- for (Struct_field_list::iterator p = fields->begin();
- p != fields->end();
- ++p)
- {
- Type* t = p->type();
- if (t->is_undefined())
- {
- error_at(p->location(), "struct field type is incomplete");
- p->set_type(Type::make_error_type());
- }
- else if (p->is_anonymous())
- {
- if (t->named_type() != NULL && t->points_to() != NULL)
- {
- error_at(p->location(), "embedded type may not be a pointer");
- p->set_type(Type::make_error_type());
- }
- else if (t->points_to() != NULL
- && t->points_to()->interface_type() != NULL)
- {
- error_at(p->location(),
- "embedded type may not be pointer to interface");
- p->set_type(Type::make_error_type());
- }
- }
- }
- return true;
-}
-
-// Whether this contains a pointer.
-
-bool
-Struct_type::do_has_pointer() const
-{
- const Struct_field_list* fields = this->fields();
- if (fields == NULL)
- return false;
- for (Struct_field_list::const_iterator p = fields->begin();
- p != fields->end();
- ++p)
- {
- if (p->type()->has_pointer())
- return true;
- }
- return false;
-}
-
-// Whether this type is identical to T.
-
-bool
-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();
- if (fields1 == NULL || fields2 == NULL)
- return fields1 == fields2;
- Struct_field_list::const_iterator pf2 = fields2->begin();
- for (Struct_field_list::const_iterator pf1 = fields1->begin();
- pf1 != fields1->end();
- ++pf1, ++pf2)
- {
- if (pf2 == fields2->end())
- return false;
- if (pf1->field_name() != pf2->field_name())
- return false;
- if (pf1->is_anonymous() != pf2->is_anonymous()
- || !Type::are_identical(pf1->type(), pf2->type(),
- errors_are_identical, NULL))
- return false;
- if (!pf1->has_tag())
- {
- if (pf2->has_tag())
- return false;
- }
- else
- {
- if (!pf2->has_tag())
- return false;
- if (pf1->tag() != pf2->tag())
- return false;
- }
- }
- if (pf2 != fields2->end())
- return false;
- return true;
-}
-
-// Whether this struct type has any hidden fields.
-
-bool
-Struct_type::struct_has_hidden_fields(const Named_type* within,
- std::string* reason) const
-{
- const Struct_field_list* fields = this->fields();
- if (fields == NULL)
- return false;
- const Package* within_package = (within == NULL
- ? NULL
- : within->named_object()->package());
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf)
- {
- if (within_package != NULL
- && !pf->is_anonymous()
- && Gogo::is_hidden_name(pf->field_name()))
- {
- if (reason != NULL)
- {
- std::string within_name = within->named_object()->message_name();
- std::string name = Gogo::message_name(pf->field_name());
- size_t bufsize = 200 + within_name.length() + name.length();
- char* buf = new char[bufsize];
- snprintf(buf, bufsize,
- _("implicit assignment of %s%s%s hidden field %s%s%s"),
- open_quote, within_name.c_str(), close_quote,
- open_quote, name.c_str(), close_quote);
- reason->assign(buf);
- delete[] buf;
- }
- return true;
- }
-
- if (pf->type()->has_hidden_fields(within, reason))
- return true;
- }
-
- return false;
-}
-
-// Whether comparisons of this struct type are simple identity
-// comparisons.
-
-bool
-Struct_type::do_compare_is_identity(Gogo* gogo)
-{
- const Struct_field_list* fields = this->fields_;
- if (fields == NULL)
- return true;
- unsigned int offset = 0;
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf)
- {
- if (Gogo::is_sink_name(pf->field_name()))
- return false;
-
- if (!pf->type()->compare_is_identity(gogo))
- return false;
-
- unsigned int field_align;
- if (!pf->type()->backend_type_align(gogo, &field_align))
- return false;
- if ((offset & (field_align - 1)) != 0)
- {
- // This struct has padding. We don't guarantee that that
- // padding is zero-initialized for a stack variable, so we
- // can't use memcmp to compare struct values.
- return false;
- }
-
- unsigned int field_size;
- if (!pf->type()->backend_type_size(gogo, &field_size))
- return false;
- offset += field_size;
- }
-
- unsigned int struct_size;
- if (!this->backend_type_size(gogo, &struct_size))
- return false;
- if (offset != struct_size)
- {
- // Trailing padding may not be zero when on the stack.
- return false;
- }
-
- return true;
-}
-
-// Build identity and hash functions for this struct.
-
-// Hash code.
-
-unsigned int
-Struct_type::do_hash_for_method(Gogo* gogo) const
-{
- unsigned int ret = 0;
- if (this->fields() != NULL)
- {
- for (Struct_field_list::const_iterator pf = this->fields()->begin();
- pf != this->fields()->end();
- ++pf)
- ret = (ret << 1) + pf->type()->hash_for_method(gogo);
- }
- return ret <<= 2;
-}
-
-// Find the local field NAME.
-
-const Struct_field*
-Struct_type::find_local_field(const std::string& name,
- unsigned int *pindex) const
-{
- const Struct_field_list* fields = this->fields_;
- if (fields == NULL)
- return NULL;
- unsigned int i = 0;
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf, ++i)
- {
- if (pf->is_field_name(name))
- {
- if (pindex != NULL)
- *pindex = i;
- return &*pf;
- }
- }
- return NULL;
-}
-
-// Return an expression for field NAME in STRUCT_EXPR, or NULL.
-
-Field_reference_expression*
-Struct_type::field_reference(Expression* struct_expr, const std::string& name,
- Location location) const
-{
- unsigned int depth;
- return this->field_reference_depth(struct_expr, name, location, NULL,
- &depth);
-}
-
-// Return an expression for a field, along with the depth at which it
-// was found.
-
-Field_reference_expression*
-Struct_type::field_reference_depth(Expression* struct_expr,
- const std::string& name,
- Location location,
- Saw_named_type* saw,
- unsigned int* depth) const
-{
- const Struct_field_list* fields = this->fields_;
- if (fields == NULL)
- return NULL;
-
- // Look for a field with this name.
- unsigned int i = 0;
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf, ++i)
- {
- if (pf->is_field_name(name))
- {
- *depth = 0;
- return Expression::make_field_reference(struct_expr, i, location);
- }
- }
-
- // Look for an anonymous field which contains a field with this
- // name.
- unsigned int found_depth = 0;
- Field_reference_expression* ret = NULL;
- i = 0;
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf, ++i)
- {
- if (!pf->is_anonymous())
- continue;
-
- Struct_type* st = pf->type()->deref()->struct_type();
- if (st == NULL)
- continue;
-
- Saw_named_type* hold_saw = saw;
- Saw_named_type saw_here;
- Named_type* nt = pf->type()->named_type();
- if (nt == NULL)
- nt = pf->type()->deref()->named_type();
- if (nt != NULL)
- {
- Saw_named_type* q;
- for (q = saw; q != NULL; q = q->next)
- {
- if (q->nt == nt)
- {
- // If this is an error, it will be reported
- // elsewhere.
- break;
- }
- }
- if (q != NULL)
- continue;
- saw_here.next = saw;
- saw_here.nt = nt;
- saw = &saw_here;
- }
-
- // Look for a reference using a NULL struct expression. If we
- // find one, fill in the struct expression with a reference to
- // this field.
- unsigned int subdepth;
- Field_reference_expression* sub = st->field_reference_depth(NULL, name,
- location,
- saw,
- &subdepth);
-
- saw = hold_saw;
-
- if (sub == NULL)
- continue;
-
- if (ret == NULL || subdepth < found_depth)
- {
- if (ret != NULL)
- delete ret;
- ret = sub;
- found_depth = subdepth;
- Expression* here = Expression::make_field_reference(struct_expr, i,
- location);
- if (pf->type()->points_to() != NULL)
- here = Expression::make_unary(OPERATOR_MULT, here, location);
- while (sub->expr() != NULL)
- {
- sub = sub->expr()->deref()->field_reference_expression();
- go_assert(sub != NULL);
- }
- sub->set_struct_expression(here);
- }
- else if (subdepth > found_depth)
- delete sub;
- else
- {
- // We do not handle ambiguity here--it should be handled by
- // Type::bind_field_or_method.
- delete sub;
- found_depth = 0;
- ret = NULL;
- }
- }
-
- if (ret != NULL)
- *depth = found_depth + 1;
-
- return ret;
-}
-
-// Return the total number of fields, including embedded fields.
-
-unsigned int
-Struct_type::total_field_count() const
-{
- if (this->fields_ == NULL)
- return 0;
- unsigned int ret = 0;
- for (Struct_field_list::const_iterator pf = this->fields_->begin();
- pf != this->fields_->end();
- ++pf)
- {
- if (!pf->is_anonymous() || pf->type()->struct_type() == NULL)
- ++ret;
- else
- ret += pf->type()->struct_type()->total_field_count();
- }
- return ret;
-}
-
-// Return whether NAME is an unexported field, for better error reporting.
-
-bool
-Struct_type::is_unexported_local_field(Gogo* gogo,
- const std::string& name) const
-{
- const Struct_field_list* fields = this->fields_;
- if (fields != NULL)
- {
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf)
- {
- const std::string& field_name(pf->field_name());
- if (Gogo::is_hidden_name(field_name)
- && name == Gogo::unpack_hidden_name(field_name)
- && gogo->pack_hidden_name(name, false) != field_name)
- return true;
- }
- }
- return false;
-}
-
-// Finalize the methods of an unnamed struct.
-
-void
-Struct_type::finalize_methods(Gogo* gogo)
-{
- if (this->all_methods_ != NULL)
- return;
-
- // It is possible to have multiple identical structs that have
- // methods. We want them to share method tables. Otherwise we will
- // emit identical methods more than once, which is bad since they
- // will even have the same names.
- std::pair<Identical_structs::iterator, bool> ins =
- Struct_type::identical_structs.insert(std::make_pair(this, this));
- if (!ins.second)
- {
- // An identical struct was already entered into the hash table.
- // Note that finalize_methods is, fortunately, not recursive.
- this->all_methods_ = ins.first->second->all_methods_;
- return;
- }
-
- Type::finalize_methods(gogo, this, this->location_, &this->all_methods_);
-}
-
-// Return the method NAME, or NULL if there isn't one or if it is
-// ambiguous. Set *IS_AMBIGUOUS if the method exists but is
-// ambiguous.
-
-Method*
-Struct_type::method_function(const std::string& name, bool* is_ambiguous) const
-{
- return Type::method_function(this->all_methods_, name, is_ambiguous);
-}
-
-// Return a pointer to the interface method table for this type for
-// the interface INTERFACE. IS_POINTER is true if this is for a
-// pointer to THIS.
-
-tree
-Struct_type::interface_method_table(Gogo* gogo,
- const Interface_type* interface,
- bool is_pointer)
-{
- return Type::interface_method_table(gogo, this, interface, is_pointer,
- &this->interface_method_tables_,
- &this->pointer_interface_method_tables_);
-}
-
-// Convert struct fields to the backend representation. This is not
-// declared in types.h so that types.h doesn't have to #include
-// backend.h.
-
-static void
-get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
- bool use_placeholder,
- std::vector<Backend::Btyped_identifier>* bfields)
-{
- bfields->resize(fields->size());
- size_t i = 0;
- for (Struct_field_list::const_iterator p = fields->begin();
- p != fields->end();
- ++p, ++i)
- {
- (*bfields)[i].name = Gogo::unpack_hidden_name(p->field_name());
- (*bfields)[i].btype = (use_placeholder
- ? p->type()->get_backend_placeholder(gogo)
- : p->type()->get_backend(gogo));
- (*bfields)[i].location = p->location();
- }
- go_assert(i == fields->size());
-}
-
-// Get the tree for a struct type.
-
-Btype*
-Struct_type::do_get_backend(Gogo* gogo)
-{
- std::vector<Backend::Btyped_identifier> bfields;
- get_backend_struct_fields(gogo, this->fields_, false, &bfields);
- return gogo->backend()->struct_type(bfields);
-}
-
-// Finish the backend representation of the fields of a struct.
-
-void
-Struct_type::finish_backend_fields(Gogo* gogo)
-{
- const Struct_field_list* fields = this->fields_;
- if (fields != NULL)
- {
- for (Struct_field_list::const_iterator p = fields->begin();
- p != fields->end();
- ++p)
- p->type()->get_backend(gogo);
- }
-}
-
-// The type of a struct type descriptor.
-
-Type*
-Struct_type::make_struct_type_descriptor_type()
-{
- static Type* ret;
- if (ret == NULL)
- {
- Type* tdt = Type::make_type_descriptor_type();
- Type* ptdt = Type::make_type_descriptor_ptr_type();
-
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
- Type* string_type = Type::lookup_string_type();
- Type* pointer_string_type = Type::make_pointer_type(string_type);
-
- Struct_type* sf =
- Type::make_builtin_struct_type(5,
- "name", pointer_string_type,
- "pkgPath", pointer_string_type,
- "typ", ptdt,
- "tag", pointer_string_type,
- "offset", uintptr_type);
- Type* nsf = Type::make_builtin_named_type("structField", sf);
-
- Type* slice_type = Type::make_array_type(nsf, NULL);
-
- Struct_type* s = Type::make_builtin_struct_type(2,
- "", tdt,
- "fields", slice_type);
-
- ret = Type::make_builtin_named_type("StructType", s);
- }
-
- return ret;
-}
-
-// Build a type descriptor for a struct type.
-
-Expression*
-Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- Location bloc = Linemap::predeclared_location();
-
- Type* stdt = Struct_type::make_struct_type_descriptor_type();
-
- const Struct_field_list* fields = stdt->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(2);
-
- const Methods* methods = this->methods();
- // A named struct should not have methods--the methods should attach
- // to the named type.
- go_assert(methods == NULL || name == NULL);
-
- Struct_field_list::const_iterator ps = fields->begin();
- go_assert(ps->is_field_name("commonType"));
- vals->push_back(this->type_descriptor_constructor(gogo,
- RUNTIME_TYPE_KIND_STRUCT,
- name, methods, true));
-
- ++ps;
- go_assert(ps->is_field_name("fields"));
-
- Expression_list* elements = new Expression_list();
- elements->reserve(this->fields_->size());
- Type* element_type = ps->type()->array_type()->element_type();
- for (Struct_field_list::const_iterator pf = this->fields_->begin();
- pf != this->fields_->end();
- ++pf)
- {
- const Struct_field_list* f = element_type->struct_type()->fields();
-
- Expression_list* fvals = new Expression_list();
- fvals->reserve(5);
-
- Struct_field_list::const_iterator q = f->begin();
- go_assert(q->is_field_name("name"));
- if (pf->is_anonymous())
- fvals->push_back(Expression::make_nil(bloc));
- else
- {
- std::string n = Gogo::unpack_hidden_name(pf->field_name());
- Expression* s = Expression::make_string(n, bloc);
- fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
- }
-
- ++q;
- go_assert(q->is_field_name("pkgPath"));
- if (!Gogo::is_hidden_name(pf->field_name()))
- fvals->push_back(Expression::make_nil(bloc));
- else
- {
- std::string n = Gogo::hidden_name_pkgpath(pf->field_name());
- Expression* s = Expression::make_string(n, bloc);
- fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
- }
-
- ++q;
- go_assert(q->is_field_name("typ"));
- fvals->push_back(Expression::make_type_descriptor(pf->type(), bloc));
-
- ++q;
- go_assert(q->is_field_name("tag"));
- if (!pf->has_tag())
- fvals->push_back(Expression::make_nil(bloc));
- else
- {
- Expression* s = Expression::make_string(pf->tag(), bloc);
- fvals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
- }
-
- ++q;
- go_assert(q->is_field_name("offset"));
- fvals->push_back(Expression::make_struct_field_offset(this, &*pf));
-
- Expression* v = Expression::make_struct_composite_literal(element_type,
- fvals, bloc);
- elements->push_back(v);
- }
-
- vals->push_back(Expression::make_slice_composite_literal(ps->type(),
- elements, bloc));
-
- return Expression::make_struct_composite_literal(stdt, vals, bloc);
-}
-
-// Write the hash function for a struct which can not use the identity
-// function.
-
-void
-Struct_type::write_hash_function(Gogo* gogo, Named_type*,
- Function_type* hash_fntype,
- Function_type* equal_fntype)
-{
- Location bloc = Linemap::predeclared_location();
-
- // The pointer to the struct that we are going to hash. This is an
- // argument to the hash function we are implementing here.
- Named_object* key_arg = gogo->lookup("key", NULL);
- go_assert(key_arg != NULL);
- Type* key_arg_type = key_arg->var_value()->type();
-
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
-
- // Get a 0.
- mpz_t ival;
- mpz_init_set_ui(ival, 0);
- Expression* zero = Expression::make_integer(&ival, uintptr_type, bloc);
- mpz_clear(ival);
-
- // Make a temporary to hold the return value, initialized to 0.
- Temporary_statement* retval = Statement::make_temporary(uintptr_type, zero,
- bloc);
- gogo->add_statement(retval);
-
- // Make a temporary to hold the key as a uintptr.
- Expression* ref = Expression::make_var_reference(key_arg, bloc);
- ref = Expression::make_cast(uintptr_type, ref, bloc);
- Temporary_statement* key = Statement::make_temporary(uintptr_type, ref,
- bloc);
- gogo->add_statement(key);
-
- // Loop over the struct fields.
- bool first = true;
- const Struct_field_list* fields = this->fields_;
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf)
- {
- if (Gogo::is_sink_name(pf->field_name()))
- continue;
-
- if (first)
- first = false;
- else
- {
- // Multiply retval by 33.
- mpz_init_set_ui(ival, 33);
- Expression* i33 = Expression::make_integer(&ival, uintptr_type,
- bloc);
- mpz_clear(ival);
-
- ref = Expression::make_temporary_reference(retval, bloc);
- Statement* s = Statement::make_assignment_operation(OPERATOR_MULTEQ,
- ref, i33, bloc);
- gogo->add_statement(s);
- }
-
- // Get a pointer to the value of this field.
- Expression* offset = Expression::make_struct_field_offset(this, &*pf);
- ref = Expression::make_temporary_reference(key, bloc);
- Expression* subkey = Expression::make_binary(OPERATOR_PLUS, ref, offset,
- bloc);
- subkey = Expression::make_cast(key_arg_type, subkey, bloc);
-
- // Get the size of this field.
- Expression* size = Expression::make_type_info(pf->type(),
- Expression::TYPE_INFO_SIZE);
-
- // Get the hash function to use for the type of this field.
- Named_object* hash_fn;
- Named_object* equal_fn;
- pf->type()->type_functions(gogo, pf->type()->named_type(), hash_fntype,
- equal_fntype, &hash_fn, &equal_fn);
-
- // Call the hash function for the field.
- Expression_list* args = new Expression_list();
- args->push_back(subkey);
- args->push_back(size);
- Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc);
- Expression* call = Expression::make_call(func, args, false, bloc);
-
- // Add the field's hash value to retval.
- Temporary_reference_expression* tref =
- Expression::make_temporary_reference(retval, bloc);
- tref->set_is_lvalue();
- Statement* s = Statement::make_assignment_operation(OPERATOR_PLUSEQ,
- tref, call, bloc);
- gogo->add_statement(s);
- }
-
- // Return retval to the caller of the hash function.
- Expression_list* vals = new Expression_list();
- ref = Expression::make_temporary_reference(retval, bloc);
- vals->push_back(ref);
- Statement* s = Statement::make_return_statement(vals, bloc);
- gogo->add_statement(s);
-}
-
-// Write the equality function for a struct which can not use the
-// identity function.
-
-void
-Struct_type::write_equal_function(Gogo* gogo, Named_type* name)
-{
- Location bloc = Linemap::predeclared_location();
-
- // The pointers to the structs we are going to compare.
- Named_object* key1_arg = gogo->lookup("key1", NULL);
- Named_object* key2_arg = gogo->lookup("key2", NULL);
- go_assert(key1_arg != NULL && key2_arg != NULL);
-
- // Build temporaries with the right types.
- Type* pt = Type::make_pointer_type(name != NULL
- ? static_cast<Type*>(name)
- : static_cast<Type*>(this));
-
- Expression* ref = Expression::make_var_reference(key1_arg, bloc);
- ref = Expression::make_unsafe_cast(pt, ref, bloc);
- Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc);
- gogo->add_statement(p1);
-
- ref = Expression::make_var_reference(key2_arg, bloc);
- ref = Expression::make_unsafe_cast(pt, ref, bloc);
- Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc);
- gogo->add_statement(p2);
-
- const Struct_field_list* fields = this->fields_;
- unsigned int field_index = 0;
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf, ++field_index)
- {
- if (Gogo::is_sink_name(pf->field_name()))
- continue;
-
- // Compare one field in both P1 and P2.
- Expression* f1 = Expression::make_temporary_reference(p1, bloc);
- f1 = Expression::make_unary(OPERATOR_MULT, f1, bloc);
- f1 = Expression::make_field_reference(f1, field_index, bloc);
-
- Expression* f2 = Expression::make_temporary_reference(p2, bloc);
- f2 = Expression::make_unary(OPERATOR_MULT, f2, bloc);
- f2 = Expression::make_field_reference(f2, field_index, bloc);
-
- Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, f1, f2, bloc);
-
- // If the values are not equal, return false.
- gogo->start_block(bloc);
- Expression_list* vals = new Expression_list();
- vals->push_back(Expression::make_boolean(false, bloc));
- Statement* s = Statement::make_return_statement(vals, bloc);
- gogo->add_statement(s);
- Block* then_block = gogo->finish_block(bloc);
-
- s = Statement::make_if_statement(cond, then_block, NULL, bloc);
- gogo->add_statement(s);
- }
-
- // All the fields are equal, so return true.
- Expression_list* vals = new Expression_list();
- vals->push_back(Expression::make_boolean(true, bloc));
- Statement* s = Statement::make_return_statement(vals, bloc);
- gogo->add_statement(s);
-}
-
-// Reflection string.
-
-void
-Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
-{
- ret->append("struct {");
-
- for (Struct_field_list::const_iterator p = this->fields_->begin();
- p != this->fields_->end();
- ++p)
- {
- if (p != this->fields_->begin())
- ret->push_back(';');
- ret->push_back(' ');
- if (p->is_anonymous())
- ret->push_back('?');
- else
- ret->append(Gogo::unpack_hidden_name(p->field_name()));
- ret->push_back(' ');
- this->append_reflection(p->type(), gogo, ret);
-
- if (p->has_tag())
- {
- const std::string& tag(p->tag());
- ret->append(" \"");
- for (std::string::const_iterator p = tag.begin();
- p != tag.end();
- ++p)
- {
- if (*p == '\0')
- ret->append("\\x00");
- else if (*p == '\n')
- ret->append("\\n");
- else if (*p == '\t')
- ret->append("\\t");
- else if (*p == '"')
- ret->append("\\\"");
- else if (*p == '\\')
- ret->append("\\\\");
- else
- ret->push_back(*p);
- }
- ret->push_back('"');
- }
- }
-
- if (!this->fields_->empty())
- ret->push_back(' ');
-
- ret->push_back('}');
-}
-
-// Mangled name.
-
-void
-Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('S');
-
- const Struct_field_list* fields = this->fields_;
- if (fields != NULL)
- {
- for (Struct_field_list::const_iterator p = fields->begin();
- p != fields->end();
- ++p)
- {
- if (p->is_anonymous())
- ret->append("0_");
- else
- {
- std::string n = Gogo::unpack_hidden_name(p->field_name());
- char buf[20];
- snprintf(buf, sizeof buf, "%u_",
- static_cast<unsigned int>(n.length()));
- ret->append(buf);
- ret->append(n);
- }
- this->append_mangled_name(p->type(), gogo, ret);
- if (p->has_tag())
- {
- const std::string& tag(p->tag());
- std::string out;
- for (std::string::const_iterator p = tag.begin();
- p != tag.end();
- ++p)
- {
- if (ISALNUM(*p) || *p == '_')
- out.push_back(*p);
- else
- {
- char buf[20];
- snprintf(buf, sizeof buf, ".%x.",
- static_cast<unsigned int>(*p));
- out.append(buf);
- }
- }
- char buf[20];
- snprintf(buf, sizeof buf, "T%u_",
- static_cast<unsigned int>(out.length()));
- ret->append(buf);
- ret->append(out);
- }
- }
- }
-
- ret->push_back('e');
-}
-
-// If the offset of field INDEX in the backend implementation can be
-// determined, set *POFFSET to the offset in bytes and return true.
-// Otherwise, return false.
-
-bool
-Struct_type::backend_field_offset(Gogo* gogo, unsigned int index,
- unsigned int* poffset)
-{
- if (!this->is_backend_type_size_known(gogo))
- return false;
- Btype* bt = this->get_backend_placeholder(gogo);
- size_t offset = gogo->backend()->type_field_offset(bt, index);
- *poffset = static_cast<unsigned int>(offset);
- if (*poffset != offset)
- return false;
- return true;
-}
-
-// Export.
-
-void
-Struct_type::do_export(Export* exp) const
-{
- exp->write_c_string("struct { ");
- const Struct_field_list* fields = this->fields_;
- go_assert(fields != NULL);
- for (Struct_field_list::const_iterator p = fields->begin();
- p != fields->end();
- ++p)
- {
- if (p->is_anonymous())
- exp->write_string("? ");
- else
- {
- exp->write_string(p->field_name());
- exp->write_c_string(" ");
- }
- exp->write_type(p->type());
-
- if (p->has_tag())
- {
- exp->write_c_string(" ");
- Expression* expr =
- Expression::make_string(p->tag(), Linemap::predeclared_location());
- expr->export_expression(exp);
- delete expr;
- }
-
- exp->write_c_string("; ");
- }
- exp->write_c_string("}");
-}
-
-// Import.
-
-Struct_type*
-Struct_type::do_import(Import* imp)
-{
- imp->require_c_string("struct { ");
- Struct_field_list* fields = new Struct_field_list;
- if (imp->peek_char() != '}')
- {
- while (true)
- {
- std::string name;
- if (imp->match_c_string("? "))
- imp->advance(2);
- else
- {
- name = imp->read_identifier();
- imp->require_c_string(" ");
- }
- Type* ftype = imp->read_type();
-
- Struct_field sf(Typed_identifier(name, ftype, imp->location()));
-
- if (imp->peek_char() == ' ')
- {
- imp->advance(1);
- Expression* expr = Expression::import_expression(imp);
- String_expression* sexpr = expr->string_expression();
- go_assert(sexpr != NULL);
- sf.set_tag(sexpr->val());
- delete sexpr;
- }
-
- imp->require_c_string("; ");
- fields->push_back(sf);
- if (imp->peek_char() == '}')
- break;
- }
- }
- imp->require_c_string("}");
-
- return Type::make_struct_type(fields, imp->location());
-}
-
-// Make a struct type.
-
-Struct_type*
-Type::make_struct_type(Struct_field_list* fields,
- Location location)
-{
- return new Struct_type(fields, location);
-}
-
-// Class Array_type.
-
-// Whether two array types are identical.
-
-bool
-Array_type::is_identical(const Array_type* t, bool errors_are_identical) const
-{
- if (!Type::are_identical(this->element_type(), t->element_type(),
- errors_are_identical, NULL))
- return false;
-
- Expression* l1 = this->length();
- Expression* l2 = t->length();
-
- // Slices of the same element type are identical.
- if (l1 == NULL && l2 == NULL)
- return true;
-
- // Arrays of the same element type are identical if they have the
- // same length.
- if (l1 != NULL && l2 != NULL)
- {
- if (l1 == l2)
- return true;
-
- // Try to determine the lengths. If we can't, assume the arrays
- // are not identical.
- bool ret = false;
- Numeric_constant nc1, nc2;
- if (l1->numeric_constant_value(&nc1)
- && l2->numeric_constant_value(&nc2))
- {
- mpz_t v1;
- if (nc1.to_int(&v1))
- {
- mpz_t v2;
- if (nc2.to_int(&v2))
- {
- ret = mpz_cmp(v1, v2) == 0;
- mpz_clear(v2);
- }
- mpz_clear(v1);
- }
- }
- return ret;
- }
-
- // Otherwise the arrays are not identical.
- return false;
-}
-
-// Traversal.
-
-int
-Array_type::do_traverse(Traverse* traverse)
-{
- if (Type::traverse(this->element_type_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- if (this->length_ != NULL
- && Expression::traverse(&this->length_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Check that the length is valid.
-
-bool
-Array_type::verify_length()
-{
- if (this->length_ == NULL)
- return true;
-
- Type_context context(Type::lookup_integer_type("int"), false);
- this->length_->determine_type(&context);
-
- if (!this->length_->is_constant())
- {
- error_at(this->length_->location(), "array bound is not constant");
- return false;
- }
-
- Numeric_constant nc;
- if (!this->length_->numeric_constant_value(&nc))
- {
- if (this->length_->type()->integer_type() != NULL
- || this->length_->type()->float_type() != NULL)
- error_at(this->length_->location(), "array bound is not constant");
- else
- error_at(this->length_->location(), "array bound is not numeric");
- return false;
- }
-
- unsigned long val;
- switch (nc.to_unsigned_long(&val))
- {
- case Numeric_constant::NC_UL_VALID:
- break;
- case Numeric_constant::NC_UL_NOTINT:
- error_at(this->length_->location(), "array bound truncated to integer");
- return false;
- case Numeric_constant::NC_UL_NEGATIVE:
- error_at(this->length_->location(), "negative array bound");
- return false;
- case Numeric_constant::NC_UL_BIG:
- error_at(this->length_->location(), "array bound overflows");
- return false;
- default:
- go_unreachable();
- }
-
- Type* int_type = Type::lookup_integer_type("int");
- unsigned int tbits = int_type->integer_type()->bits();
- if (sizeof(val) <= tbits * 8
- && val >> (tbits - 1) != 0)
- {
- error_at(this->length_->location(), "array bound overflows");
- return false;
- }
-
- return true;
-}
-
-// Verify the type.
-
-bool
-Array_type::do_verify()
-{
- if (!this->verify_length())
- this->length_ = Expression::make_error(this->length_->location());
- return true;
-}
-
-// Whether we can use memcmp to compare this array.
-
-bool
-Array_type::do_compare_is_identity(Gogo* gogo)
-{
- if (this->length_ == NULL)
- return false;
-
- // Check for [...], which indicates that this is not a real type.
- if (this->length_->is_nil_expression())
- return false;
-
- if (!this->element_type_->compare_is_identity(gogo))
- return false;
-
- // If there is any padding, then we can't use memcmp.
- unsigned int size;
- unsigned int align;
- if (!this->element_type_->backend_type_size(gogo, &size)
- || !this->element_type_->backend_type_align(gogo, &align))
- return false;
- if ((size & (align - 1)) != 0)
- return false;
-
- return true;
-}
-
-// Array type hash code.
-
-unsigned int
-Array_type::do_hash_for_method(Gogo* gogo) const
-{
- // There is no very convenient way to get a hash code for the
- // length.
- return this->element_type_->hash_for_method(gogo) + 1;
-}
-
-// Write the hash function for an array which can not use the identify
-// function.
-
-void
-Array_type::write_hash_function(Gogo* gogo, Named_type* name,
- Function_type* hash_fntype,
- Function_type* equal_fntype)
-{
- Location bloc = Linemap::predeclared_location();
-
- // The pointer to the array that we are going to hash. This is an
- // argument to the hash function we are implementing here.
- Named_object* key_arg = gogo->lookup("key", NULL);
- go_assert(key_arg != NULL);
- Type* key_arg_type = key_arg->var_value()->type();
-
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
-
- // Get a 0.
- mpz_t ival;
- mpz_init_set_ui(ival, 0);
- Expression* zero = Expression::make_integer(&ival, uintptr_type, bloc);
- mpz_clear(ival);
-
- // Make a temporary to hold the return value, initialized to 0.
- Temporary_statement* retval = Statement::make_temporary(uintptr_type, zero,
- bloc);
- gogo->add_statement(retval);
-
- // Make a temporary to hold the key as a uintptr.
- Expression* ref = Expression::make_var_reference(key_arg, bloc);
- ref = Expression::make_cast(uintptr_type, ref, bloc);
- Temporary_statement* key = Statement::make_temporary(uintptr_type, ref,
- bloc);
- gogo->add_statement(key);
-
- // Loop over the array elements.
- // for i = range a
- Type* int_type = Type::lookup_integer_type("int");
- Temporary_statement* index = Statement::make_temporary(int_type, NULL, bloc);
- gogo->add_statement(index);
-
- Expression* iref = Expression::make_temporary_reference(index, bloc);
- Expression* aref = Expression::make_var_reference(key_arg, bloc);
- Type* pt = Type::make_pointer_type(name != NULL
- ? static_cast<Type*>(name)
- : static_cast<Type*>(this));
- aref = Expression::make_cast(pt, aref, bloc);
- For_range_statement* for_range = Statement::make_for_range_statement(iref,
- NULL,
- aref,
- bloc);
-
- gogo->start_block(bloc);
-
- // Multiply retval by 33.
- mpz_init_set_ui(ival, 33);
- Expression* i33 = Expression::make_integer(&ival, uintptr_type, bloc);
- mpz_clear(ival);
-
- ref = Expression::make_temporary_reference(retval, bloc);
- Statement* s = Statement::make_assignment_operation(OPERATOR_MULTEQ, ref,
- i33, bloc);
- gogo->add_statement(s);
-
- // Get the hash function for the element type.
- Named_object* hash_fn;
- Named_object* equal_fn;
- this->element_type_->type_functions(gogo, this->element_type_->named_type(),
- hash_fntype, equal_fntype, &hash_fn,
- &equal_fn);
-
- // Get a pointer to this element in the loop.
- Expression* subkey = Expression::make_temporary_reference(key, bloc);
- subkey = Expression::make_cast(key_arg_type, subkey, bloc);
-
- // Get the size of each element.
- Expression* ele_size = Expression::make_type_info(this->element_type_,
- Expression::TYPE_INFO_SIZE);
-
- // Get the hash of this element.
- Expression_list* args = new Expression_list();
- args->push_back(subkey);
- args->push_back(ele_size);
- Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc);
- Expression* call = Expression::make_call(func, args, false, bloc);
-
- // Add the element's hash value to retval.
- Temporary_reference_expression* tref =
- Expression::make_temporary_reference(retval, bloc);
- tref->set_is_lvalue();
- s = Statement::make_assignment_operation(OPERATOR_PLUSEQ, tref, call, bloc);
- gogo->add_statement(s);
-
- // Increase the element pointer.
- tref = Expression::make_temporary_reference(key, bloc);
- tref->set_is_lvalue();
- s = Statement::make_assignment_operation(OPERATOR_PLUSEQ, tref, ele_size,
- bloc);
-
- Block* statements = gogo->finish_block(bloc);
-
- for_range->add_statements(statements);
- gogo->add_statement(for_range);
-
- // Return retval to the caller of the hash function.
- Expression_list* vals = new Expression_list();
- ref = Expression::make_temporary_reference(retval, bloc);
- vals->push_back(ref);
- s = Statement::make_return_statement(vals, bloc);
- gogo->add_statement(s);
-}
-
-// Write the equality function for an array which can not use the
-// identity function.
-
-void
-Array_type::write_equal_function(Gogo* gogo, Named_type* name)
-{
- Location bloc = Linemap::predeclared_location();
-
- // The pointers to the arrays we are going to compare.
- Named_object* key1_arg = gogo->lookup("key1", NULL);
- Named_object* key2_arg = gogo->lookup("key2", NULL);
- go_assert(key1_arg != NULL && key2_arg != NULL);
-
- // Build temporaries for the keys with the right types.
- Type* pt = Type::make_pointer_type(name != NULL
- ? static_cast<Type*>(name)
- : static_cast<Type*>(this));
-
- Expression* ref = Expression::make_var_reference(key1_arg, bloc);
- ref = Expression::make_unsafe_cast(pt, ref, bloc);
- Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc);
- gogo->add_statement(p1);
-
- ref = Expression::make_var_reference(key2_arg, bloc);
- ref = Expression::make_unsafe_cast(pt, ref, bloc);
- Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc);
- gogo->add_statement(p2);
-
- // Loop over the array elements.
- // for i = range a
- Type* int_type = Type::lookup_integer_type("int");
- Temporary_statement* index = Statement::make_temporary(int_type, NULL, bloc);
- gogo->add_statement(index);
-
- Expression* iref = Expression::make_temporary_reference(index, bloc);
- Expression* aref = Expression::make_temporary_reference(p1, bloc);
- For_range_statement* for_range = Statement::make_for_range_statement(iref,
- NULL,
- aref,
- bloc);
-
- gogo->start_block(bloc);
-
- // Compare element in P1 and P2.
- Expression* e1 = Expression::make_temporary_reference(p1, bloc);
- e1 = Expression::make_unary(OPERATOR_MULT, e1, bloc);
- ref = Expression::make_temporary_reference(index, bloc);
- e1 = Expression::make_array_index(e1, ref, NULL, bloc);
-
- Expression* e2 = Expression::make_temporary_reference(p2, bloc);
- e2 = Expression::make_unary(OPERATOR_MULT, e2, bloc);
- ref = Expression::make_temporary_reference(index, bloc);
- e2 = Expression::make_array_index(e2, ref, NULL, bloc);
-
- Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, e1, e2, bloc);
-
- // If the elements are not equal, return false.
- gogo->start_block(bloc);
- Expression_list* vals = new Expression_list();
- vals->push_back(Expression::make_boolean(false, bloc));
- Statement* s = Statement::make_return_statement(vals, bloc);
- gogo->add_statement(s);
- Block* then_block = gogo->finish_block(bloc);
-
- s = Statement::make_if_statement(cond, then_block, NULL, bloc);
- gogo->add_statement(s);
-
- Block* statements = gogo->finish_block(bloc);
-
- for_range->add_statements(statements);
- gogo->add_statement(for_range);
-
- // All the elements are equal, so return true.
- vals = new Expression_list();
- vals->push_back(Expression::make_boolean(true, bloc));
- s = Statement::make_return_statement(vals, bloc);
- gogo->add_statement(s);
-}
-
-// Get a tree for the length of a fixed array. The length may be
-// computed using a function call, so we must only evaluate it once.
-
-tree
-Array_type::get_length_tree(Gogo* gogo)
-{
- go_assert(this->length_ != NULL);
- if (this->length_tree_ == NULL_TREE)
- {
- Numeric_constant nc;
- mpz_t val;
- if (this->length_->numeric_constant_value(&nc) && nc.to_int(&val))
- {
- if (mpz_sgn(val) < 0)
- {
- this->length_tree_ = error_mark_node;
- return this->length_tree_;
- }
- Type* t = nc.type();
- if (t == NULL)
- t = Type::lookup_integer_type("int");
- else if (t->is_abstract())
- t = t->make_non_abstract_type();
- tree tt = type_to_tree(t->get_backend(gogo));
- this->length_tree_ = Expression::integer_constant_tree(val, tt);
- mpz_clear(val);
- }
- else
- {
- // Make up a translation context for the array length
- // expression. FIXME: This won't work in general.
- Translate_context context(gogo, NULL, NULL, NULL);
- tree len = this->length_->get_tree(&context);
- if (len != error_mark_node)
- {
- Type* int_type = Type::lookup_integer_type("int");
- tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
- len = convert_to_integer(int_type_tree, len);
- len = save_expr(len);
- }
- this->length_tree_ = len;
- }
- }
- return this->length_tree_;
-}
-
-// Get the backend representation of the fields of a slice. This is
-// not declared in types.h so that types.h doesn't have to #include
-// backend.h.
-//
-// We use int for the count and capacity fields. This matches 6g.
-// The language more or less assumes that we can't allocate space of a
-// size which does not fit in int.
-
-static void
-get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder,
- std::vector<Backend::Btyped_identifier>* bfields)
-{
- bfields->resize(3);
-
- Type* pet = Type::make_pointer_type(type->element_type());
- Btype* pbet = (use_placeholder
- ? pet->get_backend_placeholder(gogo)
- : pet->get_backend(gogo));
- Location ploc = Linemap::predeclared_location();
-
- Backend::Btyped_identifier* p = &(*bfields)[0];
- p->name = "__values";
- p->btype = pbet;
- p->location = ploc;
-
- Type* int_type = Type::lookup_integer_type("int");
-
- p = &(*bfields)[1];
- p->name = "__count";
- p->btype = int_type->get_backend(gogo);
- p->location = ploc;
-
- p = &(*bfields)[2];
- p->name = "__capacity";
- p->btype = int_type->get_backend(gogo);
- p->location = ploc;
-}
-
-// Get a tree for the type of this array. A fixed array is simply
-// represented as ARRAY_TYPE with the appropriate index--i.e., it is
-// just like an array in C. An open array is a struct with three
-// fields: a data pointer, the length, and the capacity.
-
-Btype*
-Array_type::do_get_backend(Gogo* gogo)
-{
- if (this->length_ == NULL)
- {
- std::vector<Backend::Btyped_identifier> bfields;
- get_backend_slice_fields(gogo, this, false, &bfields);
- return gogo->backend()->struct_type(bfields);
- }
- else
- {
- Btype* element = this->get_backend_element(gogo, false);
- Bexpression* len = this->get_backend_length(gogo);
- return gogo->backend()->array_type(element, len);
- }
-}
-
-// Return the backend representation of the element type.
-
-Btype*
-Array_type::get_backend_element(Gogo* gogo, bool use_placeholder)
-{
- if (use_placeholder)
- return this->element_type_->get_backend_placeholder(gogo);
- else
- return this->element_type_->get_backend(gogo);
-}
-
-// Return the backend representation of the length.
-
-Bexpression*
-Array_type::get_backend_length(Gogo* gogo)
-{
- return tree_to_expr(this->get_length_tree(gogo));
-}
-
-// Finish backend representation of the array.
-
-void
-Array_type::finish_backend_element(Gogo* gogo)
-{
- Type* et = this->array_type()->element_type();
- et->get_backend(gogo);
- if (this->is_slice_type())
- {
- // This relies on the fact that we always use the same
- // structure for a pointer to any given type.
- Type* pet = Type::make_pointer_type(et);
- pet->get_backend(gogo);
- }
-}
-
-// Return a tree for a pointer to the values in ARRAY.
-
-tree
-Array_type::value_pointer_tree(Gogo*, tree array) const
-{
- tree ret;
- if (this->length() != NULL)
- {
- // Fixed array.
- ret = fold_convert(build_pointer_type(TREE_TYPE(TREE_TYPE(array))),
- build_fold_addr_expr(array));
- }
- else
- {
- // Open array.
- tree field = TYPE_FIELDS(TREE_TYPE(array));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
- "__values") == 0);
- ret = fold_build3(COMPONENT_REF, TREE_TYPE(field), array, field,
- NULL_TREE);
- }
- if (TREE_CONSTANT(array))
- TREE_CONSTANT(ret) = 1;
- return ret;
-}
-
-// Return a tree for the length of the array ARRAY which has this
-// type.
-
-tree
-Array_type::length_tree(Gogo* gogo, tree array)
-{
- if (this->length_ != NULL)
- {
- if (TREE_CODE(array) == SAVE_EXPR)
- return this->get_length_tree(gogo);
- else
- {
- tree len = this->get_length_tree(gogo);
- return omit_one_operand(TREE_TYPE(len), len, array);
- }
- }
-
- // This is an open array. We need to read the length field.
-
- tree type = TREE_TYPE(array);
- go_assert(TREE_CODE(type) == RECORD_TYPE);
-
- tree field = DECL_CHAIN(TYPE_FIELDS(type));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
-
- tree ret = build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE);
- if (TREE_CONSTANT(array))
- TREE_CONSTANT(ret) = 1;
- return ret;
-}
-
-// Return a tree for the capacity of the array ARRAY which has this
-// type.
-
-tree
-Array_type::capacity_tree(Gogo* gogo, tree array)
-{
- if (this->length_ != NULL)
- {
- tree len = this->get_length_tree(gogo);
- return omit_one_operand(TREE_TYPE(len), len, array);
- }
-
- // This is an open array. We need to read the capacity field.
-
- tree type = TREE_TYPE(array);
- go_assert(TREE_CODE(type) == RECORD_TYPE);
-
- tree field = DECL_CHAIN(DECL_CHAIN(TYPE_FIELDS(type)));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
-
- return build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE);
-}
-
-// Export.
-
-void
-Array_type::do_export(Export* exp) const
-{
- exp->write_c_string("[");
- if (this->length_ != NULL)
- this->length_->export_expression(exp);
- exp->write_c_string("] ");
- exp->write_type(this->element_type_);
-}
-
-// Import.
-
-Array_type*
-Array_type::do_import(Import* imp)
-{
- imp->require_c_string("[");
- Expression* length;
- if (imp->peek_char() == ']')
- length = NULL;
- else
- length = Expression::import_expression(imp);
- imp->require_c_string("] ");
- Type* element_type = imp->read_type();
- return Type::make_array_type(element_type, length);
-}
-
-// The type of an array type descriptor.
-
-Type*
-Array_type::make_array_type_descriptor_type()
-{
- static Type* ret;
- if (ret == NULL)
- {
- Type* tdt = Type::make_type_descriptor_type();
- Type* ptdt = Type::make_type_descriptor_ptr_type();
-
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
-
- Struct_type* sf =
- Type::make_builtin_struct_type(4,
- "", tdt,
- "elem", ptdt,
- "slice", ptdt,
- "len", uintptr_type);
-
- ret = Type::make_builtin_named_type("ArrayType", sf);
- }
-
- return ret;
-}
-
-// The type of an slice type descriptor.
-
-Type*
-Array_type::make_slice_type_descriptor_type()
-{
- static Type* ret;
- if (ret == NULL)
- {
- Type* tdt = Type::make_type_descriptor_type();
- Type* ptdt = Type::make_type_descriptor_ptr_type();
-
- Struct_type* sf =
- Type::make_builtin_struct_type(2,
- "", tdt,
- "elem", ptdt);
-
- ret = Type::make_builtin_named_type("SliceType", sf);
- }
-
- return ret;
-}
-
-// Build a type descriptor for an array/slice type.
-
-Expression*
-Array_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- if (this->length_ != NULL)
- return this->array_type_descriptor(gogo, name);
- else
- return this->slice_type_descriptor(gogo, name);
-}
-
-// Build a type descriptor for an array type.
-
-Expression*
-Array_type::array_type_descriptor(Gogo* gogo, Named_type* name)
-{
- Location bloc = Linemap::predeclared_location();
-
- Type* atdt = Array_type::make_array_type_descriptor_type();
-
- const Struct_field_list* fields = atdt->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(3);
-
- Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("commonType"));
- vals->push_back(this->type_descriptor_constructor(gogo,
- RUNTIME_TYPE_KIND_ARRAY,
- name, NULL, true));
-
- ++p;
- go_assert(p->is_field_name("elem"));
- vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc));
-
- ++p;
- go_assert(p->is_field_name("slice"));
- Type* slice_type = Type::make_array_type(this->element_type_, NULL);
- vals->push_back(Expression::make_type_descriptor(slice_type, bloc));
-
- ++p;
- go_assert(p->is_field_name("len"));
- vals->push_back(Expression::make_cast(p->type(), this->length_, bloc));
-
- ++p;
- go_assert(p == fields->end());
-
- return Expression::make_struct_composite_literal(atdt, vals, bloc);
-}
-
-// Build a type descriptor for a slice type.
-
-Expression*
-Array_type::slice_type_descriptor(Gogo* gogo, Named_type* name)
-{
- Location bloc = Linemap::predeclared_location();
-
- Type* stdt = Array_type::make_slice_type_descriptor_type();
-
- const Struct_field_list* fields = stdt->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(2);
-
- Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("commonType"));
- vals->push_back(this->type_descriptor_constructor(gogo,
- RUNTIME_TYPE_KIND_SLICE,
- name, NULL, true));
-
- ++p;
- go_assert(p->is_field_name("elem"));
- vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc));
-
- ++p;
- go_assert(p == fields->end());
-
- return Expression::make_struct_composite_literal(stdt, vals, bloc);
-}
-
-// Reflection string.
-
-void
-Array_type::do_reflection(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('[');
- if (this->length_ != NULL)
- {
- Numeric_constant nc;
- unsigned long val;
- if (!this->length_->numeric_constant_value(&nc)
- || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
- error_at(this->length_->location(), "invalid array length");
- else
- {
- char buf[50];
- snprintf(buf, sizeof buf, "%lu", val);
- ret->append(buf);
- }
- }
- ret->push_back(']');
-
- this->append_reflection(this->element_type_, gogo, ret);
-}
-
-// Mangled name.
-
-void
-Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('A');
- this->append_mangled_name(this->element_type_, gogo, ret);
- if (this->length_ != NULL)
- {
- Numeric_constant nc;
- unsigned long val;
- if (!this->length_->numeric_constant_value(&nc)
- || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
- error_at(this->length_->location(), "invalid array length");
- else
- {
- char buf[50];
- snprintf(buf, sizeof buf, "%lu", val);
- ret->append(buf);
- }
- }
- ret->push_back('e');
-}
-
-// Make an array type.
-
-Array_type*
-Type::make_array_type(Type* element_type, Expression* length)
-{
- return new Array_type(element_type, length);
-}
-
-// Class Map_type.
-
-// Traversal.
-
-int
-Map_type::do_traverse(Traverse* traverse)
-{
- if (Type::traverse(this->key_type_, traverse) == TRAVERSE_EXIT
- || Type::traverse(this->val_type_, traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Check that the map type is OK.
-
-bool
-Map_type::do_verify()
-{
- // The runtime support uses "map[void]void".
- if (!this->key_type_->is_comparable() && !this->key_type_->is_void_type())
- error_at(this->location_, "invalid map key type");
- return true;
-}
-
-// Whether two map types are identical.
-
-bool
-Map_type::is_identical(const Map_type* t, bool errors_are_identical) const
-{
- 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.
-
-unsigned int
-Map_type::do_hash_for_method(Gogo* gogo) const
-{
- return (this->key_type_->hash_for_method(gogo)
- + this->val_type_->hash_for_method(gogo)
- + 2);
-}
-
-// Get the backend representation for a map type. A map type is
-// represented as a pointer to a struct. The struct is __go_map in
-// libgo/map.h.
-
-Btype*
-Map_type::do_get_backend(Gogo* gogo)
-{
- static Btype* backend_map_type;
- if (backend_map_type == NULL)
- {
- std::vector<Backend::Btyped_identifier> bfields(4);
-
- Location bloc = Linemap::predeclared_location();
-
- Type* pdt = Type::make_type_descriptor_ptr_type();
- bfields[0].name = "__descriptor";
- bfields[0].btype = pdt->get_backend(gogo);
- bfields[0].location = bloc;
-
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
- bfields[1].name = "__element_count";
- bfields[1].btype = uintptr_type->get_backend(gogo);
- bfields[1].location = bloc;
-
- bfields[2].name = "__bucket_count";
- bfields[2].btype = bfields[1].btype;
- bfields[2].location = bloc;
-
- Btype* bvt = gogo->backend()->void_type();
- Btype* bpvt = gogo->backend()->pointer_type(bvt);
- Btype* bppvt = gogo->backend()->pointer_type(bpvt);
- bfields[3].name = "__buckets";
- bfields[3].btype = bppvt;
- bfields[3].location = bloc;
-
- Btype *bt = gogo->backend()->struct_type(bfields);
- bt = gogo->backend()->named_type("__go_map", bt, bloc);
- backend_map_type = gogo->backend()->pointer_type(bt);
- }
- return backend_map_type;
-}
-
-// The type of a map type descriptor.
-
-Type*
-Map_type::make_map_type_descriptor_type()
-{
- static Type* ret;
- if (ret == NULL)
- {
- Type* tdt = Type::make_type_descriptor_type();
- Type* ptdt = Type::make_type_descriptor_ptr_type();
-
- Struct_type* sf =
- Type::make_builtin_struct_type(3,
- "", tdt,
- "key", ptdt,
- "elem", ptdt);
-
- ret = Type::make_builtin_named_type("MapType", sf);
- }
-
- return ret;
-}
-
-// Build a type descriptor for a map type.
-
-Expression*
-Map_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- Location bloc = Linemap::predeclared_location();
-
- Type* mtdt = Map_type::make_map_type_descriptor_type();
-
- const Struct_field_list* fields = mtdt->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(3);
-
- Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("commonType"));
- vals->push_back(this->type_descriptor_constructor(gogo,
- RUNTIME_TYPE_KIND_MAP,
- name, NULL, true));
-
- ++p;
- go_assert(p->is_field_name("key"));
- vals->push_back(Expression::make_type_descriptor(this->key_type_, bloc));
-
- ++p;
- go_assert(p->is_field_name("elem"));
- vals->push_back(Expression::make_type_descriptor(this->val_type_, bloc));
-
- ++p;
- go_assert(p == fields->end());
-
- return Expression::make_struct_composite_literal(mtdt, vals, bloc);
-}
-
-// A mapping from map types to map descriptors.
-
-Map_type::Map_descriptors Map_type::map_descriptors;
-
-// Build a map descriptor for this type. Return a pointer to it.
-
-tree
-Map_type::map_descriptor_pointer(Gogo* gogo, Location location)
-{
- Bvariable* bvar = this->map_descriptor(gogo);
- tree var_tree = var_to_tree(bvar);
- if (var_tree == error_mark_node)
- return error_mark_node;
- return build_fold_addr_expr_loc(location.gcc_location(), var_tree);
-}
-
-// Build a map descriptor for this type.
-
-Bvariable*
-Map_type::map_descriptor(Gogo* gogo)
-{
- std::pair<Map_type*, Bvariable*> val(this, NULL);
- std::pair<Map_type::Map_descriptors::iterator, bool> ins =
- Map_type::map_descriptors.insert(val);
- if (!ins.second)
- return ins.first->second;
-
- Type* key_type = this->key_type_;
- Type* val_type = this->val_type_;
-
- // The map entry type is a struct with three fields. Build that
- // struct so that we can get the offsets of the key and value within
- // a map entry. The first field should technically be a pointer to
- // this type itself, but since we only care about field offsets we
- // just use pointer to bool.
- Type* pbool = Type::make_pointer_type(Type::make_boolean_type());
- Struct_type* map_entry_type =
- Type::make_builtin_struct_type(3,
- "__next", pbool,
- "__key", key_type,
- "__val", val_type);
-
- Type* map_descriptor_type = Map_type::make_map_descriptor_type();
-
- const Struct_field_list* fields =
- map_descriptor_type->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(4);
-
- Location bloc = Linemap::predeclared_location();
-
- Struct_field_list::const_iterator p = fields->begin();
-
- go_assert(p->is_field_name("__map_descriptor"));
- vals->push_back(Expression::make_type_descriptor(this, bloc));
-
- ++p;
- go_assert(p->is_field_name("__entry_size"));
- Expression::Type_info type_info = Expression::TYPE_INFO_SIZE;
- vals->push_back(Expression::make_type_info(map_entry_type, type_info));
-
- Struct_field_list::const_iterator pf = map_entry_type->fields()->begin();
- ++pf;
- go_assert(pf->is_field_name("__key"));
-
- ++p;
- go_assert(p->is_field_name("__key_offset"));
- vals->push_back(Expression::make_struct_field_offset(map_entry_type, &*pf));
-
- ++pf;
- go_assert(pf->is_field_name("__val"));
-
- ++p;
- go_assert(p->is_field_name("__val_offset"));
- vals->push_back(Expression::make_struct_field_offset(map_entry_type, &*pf));
-
- ++p;
- go_assert(p == fields->end());
-
- Expression* initializer =
- Expression::make_struct_composite_literal(map_descriptor_type, vals, bloc);
-
- std::string mangled_name = "__go_map_" + this->mangled_name(gogo);
- Btype* map_descriptor_btype = map_descriptor_type->get_backend(gogo);
- Bvariable* bvar = gogo->backend()->immutable_struct(mangled_name, true,
- map_descriptor_btype,
- bloc);
-
- Translate_context context(gogo, NULL, NULL, NULL);
- context.set_is_const();
- Bexpression* binitializer = tree_to_expr(initializer->get_tree(&context));
-
- gogo->backend()->immutable_struct_set_init(bvar, mangled_name, true,
- map_descriptor_btype, bloc,
- binitializer);
-
- ins.first->second = bvar;
- return bvar;
-}
-
-// Build the type of a map descriptor. This must match the struct
-// __go_map_descriptor in libgo/runtime/map.h.
-
-Type*
-Map_type::make_map_descriptor_type()
-{
- static Type* ret;
- if (ret == NULL)
- {
- Type* ptdt = Type::make_type_descriptor_ptr_type();
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
- Struct_type* sf =
- Type::make_builtin_struct_type(4,
- "__map_descriptor", ptdt,
- "__entry_size", uintptr_type,
- "__key_offset", uintptr_type,
- "__val_offset", uintptr_type);
- ret = Type::make_builtin_named_type("__go_map_descriptor", sf);
- }
- return ret;
-}
-
-// Reflection string for a map.
-
-void
-Map_type::do_reflection(Gogo* gogo, std::string* ret) const
-{
- ret->append("map[");
- this->append_reflection(this->key_type_, gogo, ret);
- ret->append("]");
- this->append_reflection(this->val_type_, gogo, ret);
-}
-
-// Mangled name for a map.
-
-void
-Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('M');
- this->append_mangled_name(this->key_type_, gogo, ret);
- ret->append("__");
- this->append_mangled_name(this->val_type_, gogo, ret);
-}
-
-// Export a map type.
-
-void
-Map_type::do_export(Export* exp) const
-{
- exp->write_c_string("map [");
- exp->write_type(this->key_type_);
- exp->write_c_string("] ");
- exp->write_type(this->val_type_);
-}
-
-// Import a map type.
-
-Map_type*
-Map_type::do_import(Import* imp)
-{
- imp->require_c_string("map [");
- Type* key_type = imp->read_type();
- imp->require_c_string("] ");
- Type* val_type = imp->read_type();
- return Type::make_map_type(key_type, val_type, imp->location());
-}
-
-// Make a map type.
-
-Map_type*
-Type::make_map_type(Type* key_type, Type* val_type, Location location)
-{
- return new Map_type(key_type, val_type, location);
-}
-
-// Class Channel_type.
-
-// Hash code.
-
-unsigned int
-Channel_type::do_hash_for_method(Gogo* gogo) const
-{
- unsigned int ret = 0;
- if (this->may_send_)
- ret += 1;
- if (this->may_receive_)
- ret += 2;
- if (this->element_type_ != NULL)
- ret += this->element_type_->hash_for_method(gogo) << 2;
- return ret << 3;
-}
-
-// Whether this type is the same as T.
-
-bool
-Channel_type::is_identical(const Channel_type* t,
- bool errors_are_identical) const
-{
- 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_);
-}
-
-// Return the tree for a channel type. A channel is a pointer to a
-// __go_channel struct. The __go_channel struct is defined in
-// libgo/runtime/channel.h.
-
-Btype*
-Channel_type::do_get_backend(Gogo* gogo)
-{
- static Btype* backend_channel_type;
- if (backend_channel_type == NULL)
- {
- std::vector<Backend::Btyped_identifier> bfields;
- Btype* bt = gogo->backend()->struct_type(bfields);
- bt = gogo->backend()->named_type("__go_channel", bt,
- Linemap::predeclared_location());
- backend_channel_type = gogo->backend()->pointer_type(bt);
- }
- return backend_channel_type;
-}
-
-// Build a type descriptor for a channel type.
-
-Type*
-Channel_type::make_chan_type_descriptor_type()
-{
- static Type* ret;
- if (ret == NULL)
- {
- Type* tdt = Type::make_type_descriptor_type();
- Type* ptdt = Type::make_type_descriptor_ptr_type();
-
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
-
- Struct_type* sf =
- Type::make_builtin_struct_type(3,
- "", tdt,
- "elem", ptdt,
- "dir", uintptr_type);
-
- ret = Type::make_builtin_named_type("ChanType", sf);
- }
-
- return ret;
-}
-
-// Build a type descriptor for a map type.
-
-Expression*
-Channel_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- Location bloc = Linemap::predeclared_location();
-
- Type* ctdt = Channel_type::make_chan_type_descriptor_type();
-
- const Struct_field_list* fields = ctdt->struct_type()->fields();
-
- Expression_list* vals = new Expression_list();
- vals->reserve(3);
-
- Struct_field_list::const_iterator p = fields->begin();
- go_assert(p->is_field_name("commonType"));
- vals->push_back(this->type_descriptor_constructor(gogo,
- RUNTIME_TYPE_KIND_CHAN,
- name, NULL, true));
-
- ++p;
- go_assert(p->is_field_name("elem"));
- vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc));
-
- ++p;
- go_assert(p->is_field_name("dir"));
- // These bits must match the ones in libgo/runtime/go-type.h.
- int val = 0;
- if (this->may_receive_)
- val |= 1;
- if (this->may_send_)
- val |= 2;
- mpz_t iv;
- mpz_init_set_ui(iv, val);
- vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
- mpz_clear(iv);
-
- ++p;
- go_assert(p == fields->end());
-
- return Expression::make_struct_composite_literal(ctdt, vals, bloc);
-}
-
-// Reflection string.
-
-void
-Channel_type::do_reflection(Gogo* gogo, std::string* ret) const
-{
- if (!this->may_send_)
- ret->append("<-");
- ret->append("chan");
- if (!this->may_receive_)
- ret->append("<-");
- ret->push_back(' ');
- this->append_reflection(this->element_type_, gogo, ret);
-}
-
-// Mangled name.
-
-void
-Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('C');
- this->append_mangled_name(this->element_type_, gogo, ret);
- if (this->may_send_)
- ret->push_back('s');
- if (this->may_receive_)
- ret->push_back('r');
- ret->push_back('e');
-}
-
-// Export.
-
-void
-Channel_type::do_export(Export* exp) const
-{
- exp->write_c_string("chan ");
- if (this->may_send_ && !this->may_receive_)
- exp->write_c_string("-< ");
- else if (this->may_receive_ && !this->may_send_)
- exp->write_c_string("<- ");
- exp->write_type(this->element_type_);
-}
-
-// Import.
-
-Channel_type*
-Channel_type::do_import(Import* imp)
-{
- imp->require_c_string("chan ");
-
- bool may_send;
- bool may_receive;
- if (imp->match_c_string("-< "))
- {
- imp->advance(3);
- may_send = true;
- may_receive = false;
- }
- else if (imp->match_c_string("<- "))
- {
- imp->advance(3);
- may_receive = true;
- may_send = false;
- }
- else
- {
- may_send = true;
- may_receive = true;
- }
-
- Type* element_type = imp->read_type();
-
- return Type::make_channel_type(may_send, may_receive, element_type);
-}
-
-// Make a new channel type.
-
-Channel_type*
-Type::make_channel_type(bool send, bool receive, Type* element_type)
-{
- return new Channel_type(send, receive, element_type);
-}
-
-// Class Interface_type.
-
-// Return the list of methods.
-
-const Typed_identifier_list*
-Interface_type::methods() const
-{
- go_assert(this->methods_are_finalized_ || saw_errors());
- return this->all_methods_;
-}
-
-// Return the number of methods.
-
-size_t
-Interface_type::method_count() const
-{
- go_assert(this->methods_are_finalized_ || saw_errors());
- return this->all_methods_ == NULL ? 0 : this->all_methods_->size();
-}
-
-// Traversal.
-
-int
-Interface_type::do_traverse(Traverse* traverse)
-{
- Typed_identifier_list* methods = (this->methods_are_finalized_
- ? this->all_methods_
- : this->parse_methods_);
- if (methods == NULL)
- return TRAVERSE_CONTINUE;
- return methods->traverse(traverse);
-}
-
-// Finalize the methods. This handles interface inheritance.
-
-void
-Interface_type::finalize_methods()
-{
- if (this->methods_are_finalized_)
- return;
- this->methods_are_finalized_ = true;
- if (this->parse_methods_ == NULL)
- return;
-
- this->all_methods_ = new Typed_identifier_list();
- this->all_methods_->reserve(this->parse_methods_->size());
- Typed_identifier_list inherit;
- for (Typed_identifier_list::const_iterator pm =
- this->parse_methods_->begin();
- pm != this->parse_methods_->end();
- ++pm)
- {
- const Typed_identifier* p = &*pm;
- if (p->name().empty())
- inherit.push_back(*p);
- else if (this->find_method(p->name()) == NULL)
- this->all_methods_->push_back(*p);
- else
- error_at(p->location(), "duplicate method %qs",
- Gogo::message_name(p->name()).c_str());
- }
-
- std::vector<Named_type*> seen;
- seen.reserve(inherit.size());
- bool issued_recursive_error = false;
- while (!inherit.empty())
- {
- Type* t = inherit.back().type();
- Location tl = inherit.back().location();
- inherit.pop_back();
-
- Interface_type* it = t->interface_type();
- if (it == NULL)
- {
- if (!t->is_error())
- error_at(tl, "interface contains embedded non-interface");
- continue;
- }
- if (it == this)
- {
- if (!issued_recursive_error)
- {
- error_at(tl, "invalid recursive interface");
- issued_recursive_error = true;
- }
- continue;
- }
-
- Named_type* nt = t->named_type();
- if (nt != NULL && it->parse_methods_ != NULL)
- {
- std::vector<Named_type*>::const_iterator q;
- for (q = seen.begin(); q != seen.end(); ++q)
- {
- if (*q == nt)
- {
- error_at(tl, "inherited interface loop");
- break;
- }
- }
- if (q != seen.end())
- continue;
- seen.push_back(nt);
- }
-
- const Typed_identifier_list* imethods = it->parse_methods_;
- if (imethods == NULL)
- continue;
- for (Typed_identifier_list::const_iterator q = imethods->begin();
- q != imethods->end();
- ++q)
- {
- if (q->name().empty())
- inherit.push_back(*q);
- else if (this->find_method(q->name()) == NULL)
- this->all_methods_->push_back(Typed_identifier(q->name(),
- q->type(), tl));
- else
- error_at(tl, "inherited method %qs is ambiguous",
- Gogo::message_name(q->name()).c_str());
- }
- }
-
- if (!this->all_methods_->empty())
- this->all_methods_->sort_by_name();
- else
- {
- delete this->all_methods_;
- this->all_methods_ = NULL;
- }
-}
-
-// Return the method NAME, or NULL.
-
-const Typed_identifier*
-Interface_type::find_method(const std::string& name) const
-{
- go_assert(this->methods_are_finalized_);
- if (this->all_methods_ == NULL)
- return NULL;
- for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
- p != this->all_methods_->end();
- ++p)
- if (p->name() == name)
- return &*p;
- return NULL;
-}
-
-// Return the method index.
-
-size_t
-Interface_type::method_index(const std::string& name) const
-{
- go_assert(this->methods_are_finalized_ && this->all_methods_ != NULL);
- size_t ret = 0;
- for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
- p != this->all_methods_->end();
- ++p, ++ret)
- if (p->name() == name)
- return ret;
- go_unreachable();
-}
-
-// Return whether NAME is an unexported method, for better error
-// reporting.
-
-bool
-Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const
-{
- go_assert(this->methods_are_finalized_);
- if (this->all_methods_ == NULL)
- return false;
- for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
- p != this->all_methods_->end();
- ++p)
- {
- const std::string& method_name(p->name());
- if (Gogo::is_hidden_name(method_name)
- && name == Gogo::unpack_hidden_name(method_name)
- && gogo->pack_hidden_name(name, false) != method_name)
- return true;
- }
- return false;
-}
-
-// Whether this type is identical with T.
-
-bool
-Interface_type::is_identical(const Interface_type* t,
- bool errors_are_identical) const
-{
- // If methods have not been finalized, then we are asking whether
- // func redeclarations are the same. This is an error, so for
- // simplicity we say they are never the same.
- if (!this->methods_are_finalized_ || !t->methods_are_finalized_)
- return false;
-
- // We require the same methods with the same types. The methods
- // have already been sorted.
- if (this->all_methods_ == NULL || t->all_methods_ == NULL)
- return this->all_methods_ == t->all_methods_;
-
- if (this->assume_identical(this, t) || t->assume_identical(t, this))
- return true;
-
- Assume_identical* hold_ai = this->assume_identical_;
- Assume_identical ai;
- ai.t1 = this;
- ai.t2 = t;
- ai.next = hold_ai;
- this->assume_identical_ = &ai;
-
- Typed_identifier_list::const_iterator p1 = this->all_methods_->begin();
- Typed_identifier_list::const_iterator p2;
- for (p2 = t->all_methods_->begin(); p2 != t->all_methods_->end(); ++p1, ++p2)
- {
- if (p1 == this->all_methods_->end())
- break;
- if (p1->name() != p2->name()
- || !Type::are_identical(p1->type(), p2->type(),
- errors_are_identical, NULL))
- break;
- }
-
- this->assume_identical_ = hold_ai;
-
- return p1 == this->all_methods_->end() && p2 == t->all_methods_->end();
-}
-
-// Return true if T1 and T2 are assumed to be identical during a type
-// comparison.
-
-bool
-Interface_type::assume_identical(const Interface_type* t1,
- const Interface_type* t2) const
-{
- for (Assume_identical* p = this->assume_identical_;
- p != NULL;
- p = p->next)
- if ((p->t1 == t1 && p->t2 == t2) || (p->t1 == t2 && p->t2 == t1))
- return true;
- return false;
-}
-
-// Whether we can assign the interface type T to this type. The types
-// are known to not be identical. An interface assignment is only
-// permitted if T is known to implement all methods in THIS.
-// Otherwise a type guard is required.
-
-bool
-Interface_type::is_compatible_for_assign(const Interface_type* t,
- std::string* reason) const
-{
- go_assert(this->methods_are_finalized_ && t->methods_are_finalized_);
- if (this->all_methods_ == NULL)
- return true;
- for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
- p != this->all_methods_->end();
- ++p)
- {
- const Typed_identifier* m = t->find_method(p->name());
- if (m == NULL)
- {
- if (reason != NULL)
- {
- char buf[200];
- snprintf(buf, sizeof buf,
- _("need explicit conversion; missing method %s%s%s"),
- open_quote, Gogo::message_name(p->name()).c_str(),
- close_quote);
- reason->assign(buf);
- }
- return false;
- }
-
- std::string subreason;
- if (!Type::are_identical(p->type(), m->type(), true, &subreason))
- {
- if (reason != NULL)
- {
- std::string n = Gogo::message_name(p->name());
- size_t len = 100 + n.length() + subreason.length();
- char* buf = new char[len];
- if (subreason.empty())
- snprintf(buf, len, _("incompatible type for method %s%s%s"),
- open_quote, n.c_str(), close_quote);
- else
- snprintf(buf, len,
- _("incompatible type for method %s%s%s (%s)"),
- open_quote, n.c_str(), close_quote,
- subreason.c_str());
- reason->assign(buf);
- delete[] buf;
- }
- return false;
- }
- }
-
- return true;
-}
-
-// Hash code.
-
-unsigned int
-Interface_type::do_hash_for_method(Gogo*) const
-{
- go_assert(this->methods_are_finalized_);
- unsigned int ret = 0;
- if (this->all_methods_ != NULL)
- {
- for (Typed_identifier_list::const_iterator p =
- this->all_methods_->begin();
- p != this->all_methods_->end();
- ++p)
- {
- ret = Type::hash_string(p->name(), ret);
- // We don't use the method type in the hash, to avoid
- // infinite recursion if an interface method uses a type
- // which is an interface which inherits from the interface
- // itself.
- // type T interface { F() interface {T}}
- ret <<= 1;
- }
- }
- return ret;
-}
-
-// Return true if T implements the interface. If it does not, and
-// REASON is not NULL, set *REASON to a useful error message.
-
-bool
-Interface_type::implements_interface(const Type* t, std::string* reason) const
-{
- go_assert(this->methods_are_finalized_);
- if (this->all_methods_ == NULL)
- return true;
-
- bool is_pointer = false;
- const Named_type* nt = t->named_type();
- const Struct_type* st = t->struct_type();
- // If we start with a named type, we don't dereference it to find
- // methods.
- if (nt == NULL)
- {
- const Type* pt = t->points_to();
- if (pt != NULL)
- {
- // If T is a pointer to a named type, then we need to look at
- // the type to which it points.
- is_pointer = true;
- nt = pt->named_type();
- st = pt->struct_type();
- }
- }
-
- // If we have a named type, get the methods from it rather than from
- // any struct type.
- if (nt != NULL)
- st = NULL;
-
- // Only named and struct types have methods.
- if (nt == NULL && st == NULL)
- {
- if (reason != NULL)
- {
- if (t->points_to() != NULL
- && t->points_to()->interface_type() != NULL)
- reason->assign(_("pointer to interface type has no methods"));
- else
- reason->assign(_("type has no methods"));
- }
- return false;
- }
-
- if (nt != NULL ? !nt->has_any_methods() : !st->has_any_methods())
- {
- if (reason != NULL)
- {
- if (t->points_to() != NULL
- && t->points_to()->interface_type() != NULL)
- reason->assign(_("pointer to interface type has no methods"));
- else
- reason->assign(_("type has no methods"));
- }
- return false;
- }
-
- for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
- p != this->all_methods_->end();
- ++p)
- {
- bool is_ambiguous = false;
- Method* m = (nt != NULL
- ? nt->method_function(p->name(), &is_ambiguous)
- : st->method_function(p->name(), &is_ambiguous));
- if (m == NULL)
- {
- if (reason != NULL)
- {
- std::string n = Gogo::message_name(p->name());
- size_t len = n.length() + 100;
- char* buf = new char[len];
- if (is_ambiguous)
- snprintf(buf, len, _("ambiguous method %s%s%s"),
- open_quote, n.c_str(), close_quote);
- else
- snprintf(buf, len, _("missing method %s%s%s"),
- open_quote, n.c_str(), close_quote);
- reason->assign(buf);
- delete[] buf;
- }
- return false;
- }
-
- Function_type *p_fn_type = p->type()->function_type();
- Function_type* m_fn_type = m->type()->function_type();
- go_assert(p_fn_type != NULL && m_fn_type != NULL);
- std::string subreason;
- if (!p_fn_type->is_identical(m_fn_type, true, true, &subreason))
- {
- if (reason != NULL)
- {
- std::string n = Gogo::message_name(p->name());
- size_t len = 100 + n.length() + subreason.length();
- char* buf = new char[len];
- if (subreason.empty())
- snprintf(buf, len, _("incompatible type for method %s%s%s"),
- open_quote, n.c_str(), close_quote);
- else
- snprintf(buf, len,
- _("incompatible type for method %s%s%s (%s)"),
- open_quote, n.c_str(), close_quote,
- subreason.c_str());
- reason->assign(buf);
- delete[] buf;
- }
- return false;
- }
-
- if (!is_pointer && !m->is_value_method())
- {
- if (reason != NULL)
- {
- std::string n = Gogo::message_name(p->name());
- size_t len = 100 + n.length();
- char* buf = new char[len];
- snprintf(buf, len,
- _("method %s%s%s requires a pointer receiver"),
- open_quote, n.c_str(), close_quote);
- reason->assign(buf);
- delete[] buf;
- }
- return false;
- }
-
- // If the magic //go:nointerface comment was used, the method
- // may not be used to implement interfaces.
- if (m->nointerface())
- {
- if (reason != NULL)
- {
- std::string n = Gogo::message_name(p->name());
- size_t len = 100 + n.length();
- char* buf = new char[len];
- snprintf(buf, len,
- _("method %s%s%s is marked go:nointerface"),
- open_quote, n.c_str(), close_quote);
- reason->assign(buf);
- delete[] buf;
- }
- return false;
- }
- }
-
- return true;
-}
-
-// Return the backend representation of the empty interface type. We
-// use the same struct for all empty interfaces.
-
-Btype*
-Interface_type::get_backend_empty_interface_type(Gogo* gogo)
-{
- static Btype* empty_interface_type;
- if (empty_interface_type == NULL)
- {
- std::vector<Backend::Btyped_identifier> bfields(2);
-
- Location bloc = Linemap::predeclared_location();
-
- Type* pdt = Type::make_type_descriptor_ptr_type();
- bfields[0].name = "__type_descriptor";
- bfields[0].btype = pdt->get_backend(gogo);
- bfields[0].location = bloc;
-
- Type* vt = Type::make_pointer_type(Type::make_void_type());
- bfields[1].name = "__object";
- bfields[1].btype = vt->get_backend(gogo);
- bfields[1].location = bloc;
-
- empty_interface_type = gogo->backend()->struct_type(bfields);
- }
- return empty_interface_type;
-}
-
-// Return the fields of a non-empty interface type. This is not
-// declared in types.h so that types.h doesn't have to #include
-// backend.h.
-
-static void
-get_backend_interface_fields(Gogo* gogo, Interface_type* type,
- bool use_placeholder,
- std::vector<Backend::Btyped_identifier>* bfields)
-{
- Location loc = type->location();
-
- std::vector<Backend::Btyped_identifier> mfields(type->methods()->size() + 1);
-
- Type* pdt = Type::make_type_descriptor_ptr_type();
- mfields[0].name = "__type_descriptor";
- mfields[0].btype = pdt->get_backend(gogo);
- mfields[0].location = loc;
-
- std::string last_name = "";
- size_t i = 1;
- for (Typed_identifier_list::const_iterator p = type->methods()->begin();
- p != type->methods()->end();
- ++p, ++i)
- {
- // The type of the method in Go only includes the parameters.
- // The actual method also has a receiver, which is always a
- // pointer. We need to add that pointer type here in order to
- // generate the correct type for the backend.
- Function_type* ft = p->type()->function_type();
- go_assert(ft->receiver() == NULL);
-
- const Typed_identifier_list* params = ft->parameters();
- Typed_identifier_list* mparams = new Typed_identifier_list();
- if (params != NULL)
- mparams->reserve(params->size() + 1);
- Type* vt = Type::make_pointer_type(Type::make_void_type());
- mparams->push_back(Typed_identifier("", vt, ft->location()));
- if (params != NULL)
- {
- for (Typed_identifier_list::const_iterator pp = params->begin();
- pp != params->end();
- ++pp)
- mparams->push_back(*pp);
- }
-
- Typed_identifier_list* mresults = (ft->results() == NULL
- ? NULL
- : ft->results()->copy());
- Function_type* mft = Type::make_function_type(NULL, mparams, mresults,
- ft->location());
-
- mfields[i].name = Gogo::unpack_hidden_name(p->name());
- mfields[i].btype = (use_placeholder
- ? mft->get_backend_placeholder(gogo)
- : mft->get_backend(gogo));
- mfields[i].location = loc;
- // Sanity check: the names should be sorted.
- go_assert(p->name() > last_name);
- last_name = p->name();
- }
-
- Btype* methods = gogo->backend()->struct_type(mfields);
-
- bfields->resize(2);
-
- (*bfields)[0].name = "__methods";
- (*bfields)[0].btype = gogo->backend()->pointer_type(methods);
- (*bfields)[0].location = loc;
-
- Type* vt = Type::make_pointer_type(Type::make_void_type());
- (*bfields)[1].name = "__object";
- (*bfields)[1].btype = vt->get_backend(gogo);
- (*bfields)[1].location = Linemap::predeclared_location();
-}
-
-// Return a tree for an interface type. An interface is a pointer to
-// a struct. The struct has three fields. The first field is a
-// pointer to the type descriptor for the dynamic type of the object.
-// The second field is a pointer to a table of methods for the
-// interface to be used with the object. The third field is the value
-// of the object itself.
-
-Btype*
-Interface_type::do_get_backend(Gogo* gogo)
-{
- if (this->is_empty())
- return Interface_type::get_backend_empty_interface_type(gogo);
- else
- {
- if (this->interface_btype_ != NULL)
- return this->interface_btype_;
- this->interface_btype_ =
- gogo->backend()->placeholder_struct_type("", this->location_);
- std::vector<Backend::Btyped_identifier> bfields;
- get_backend_interface_fields(gogo, this, false, &bfields);
- if (!gogo->backend()->set_placeholder_struct_type(this->interface_btype_,
- bfields))
- this->interface_btype_ = gogo->backend()->error_type();
- return this->interface_btype_;
- }
-}
-
-// Finish the backend representation of the methods.
-
-void
-Interface_type::finish_backend_methods(Gogo* gogo)
-{
- if (!this->interface_type()->is_empty())
- {
- const Typed_identifier_list* methods = this->methods();
- if (methods != NULL)
- {
- for (Typed_identifier_list::const_iterator p = methods->begin();
- p != methods->end();
- ++p)
- p->type()->get_backend(gogo);
- }
- }
-}
-
-// The type of an interface type descriptor.
-
-Type*
-Interface_type::make_interface_type_descriptor_type()
-{
- static Type* ret;
- if (ret == NULL)
- {
- Type* tdt = Type::make_type_descriptor_type();
- Type* ptdt = Type::make_type_descriptor_ptr_type();
-
- Type* string_type = Type::lookup_string_type();
- Type* pointer_string_type = Type::make_pointer_type(string_type);
-
- Struct_type* sm =
- Type::make_builtin_struct_type(3,
- "name", pointer_string_type,
- "pkgPath", pointer_string_type,
- "typ", ptdt);
-
- Type* nsm = Type::make_builtin_named_type("imethod", sm);
-
- Type* slice_nsm = Type::make_array_type(nsm, NULL);
-
- Struct_type* s = Type::make_builtin_struct_type(2,
- "", tdt,
- "methods", slice_nsm);
-
- ret = Type::make_builtin_named_type("InterfaceType", s);
- }
-
- return ret;
-}
-
-// Build a type descriptor for an interface type.
-
-Expression*
-Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- Location bloc = Linemap::predeclared_location();
-
- Type* itdt = Interface_type::make_interface_type_descriptor_type();
-
- const Struct_field_list* ifields = itdt->struct_type()->fields();
-
- Expression_list* ivals = new Expression_list();
- ivals->reserve(2);
-
- Struct_field_list::const_iterator pif = ifields->begin();
- go_assert(pif->is_field_name("commonType"));
- const int rt = RUNTIME_TYPE_KIND_INTERFACE;
- ivals->push_back(this->type_descriptor_constructor(gogo, rt, name, NULL,
- true));
-
- ++pif;
- go_assert(pif->is_field_name("methods"));
-
- Expression_list* methods = new Expression_list();
- if (this->all_methods_ != NULL)
- {
- Type* elemtype = pif->type()->array_type()->element_type();
-
- methods->reserve(this->all_methods_->size());
- for (Typed_identifier_list::const_iterator pm =
- this->all_methods_->begin();
- pm != this->all_methods_->end();
- ++pm)
- {
- const Struct_field_list* mfields = elemtype->struct_type()->fields();
-
- Expression_list* mvals = new Expression_list();
- mvals->reserve(3);
-
- Struct_field_list::const_iterator pmf = mfields->begin();
- go_assert(pmf->is_field_name("name"));
- std::string s = Gogo::unpack_hidden_name(pm->name());
- Expression* e = Expression::make_string(s, bloc);
- mvals->push_back(Expression::make_unary(OPERATOR_AND, e, bloc));
-
- ++pmf;
- go_assert(pmf->is_field_name("pkgPath"));
- if (!Gogo::is_hidden_name(pm->name()))
- mvals->push_back(Expression::make_nil(bloc));
- else
- {
- s = Gogo::hidden_name_pkgpath(pm->name());
- e = Expression::make_string(s, bloc);
- mvals->push_back(Expression::make_unary(OPERATOR_AND, e, bloc));
- }
-
- ++pmf;
- go_assert(pmf->is_field_name("typ"));
- mvals->push_back(Expression::make_type_descriptor(pm->type(), bloc));
-
- ++pmf;
- go_assert(pmf == mfields->end());
-
- e = Expression::make_struct_composite_literal(elemtype, mvals,
- bloc);
- methods->push_back(e);
- }
- }
-
- ivals->push_back(Expression::make_slice_composite_literal(pif->type(),
- methods, bloc));
-
- ++pif;
- go_assert(pif == ifields->end());
-
- return Expression::make_struct_composite_literal(itdt, ivals, bloc);
-}
-
-// Reflection string.
-
-void
-Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
-{
- ret->append("interface {");
- const Typed_identifier_list* methods = this->parse_methods_;
- if (methods != NULL)
- {
- ret->push_back(' ');
- for (Typed_identifier_list::const_iterator p = methods->begin();
- p != methods->end();
- ++p)
- {
- if (p != methods->begin())
- ret->append("; ");
- if (p->name().empty())
- this->append_reflection(p->type(), gogo, ret);
- else
- {
- if (!Gogo::is_hidden_name(p->name()))
- ret->append(p->name());
- else if (gogo->pkgpath_from_option())
- ret->append(p->name().substr(1));
- else
- {
- // If no -fgo-pkgpath option, backward compatibility
- // for how this used to work before -fgo-pkgpath was
- // introduced.
- std::string pkgpath = Gogo::hidden_name_pkgpath(p->name());
- ret->append(pkgpath.substr(pkgpath.find('.') + 1));
- ret->push_back('.');
- ret->append(Gogo::unpack_hidden_name(p->name()));
- }
- std::string sub = p->type()->reflection(gogo);
- go_assert(sub.compare(0, 4, "func") == 0);
- sub = sub.substr(4);
- ret->append(sub);
- }
- }
- ret->push_back(' ');
- }
- ret->append("}");
-}
-
-// Mangled name.
-
-void
-Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- go_assert(this->methods_are_finalized_);
-
- ret->push_back('I');
-
- const Typed_identifier_list* methods = this->all_methods_;
- if (methods != NULL && !this->seen_)
- {
- this->seen_ = true;
- for (Typed_identifier_list::const_iterator p = methods->begin();
- p != methods->end();
- ++p)
- {
- if (!p->name().empty())
- {
- std::string n;
- if (!Gogo::is_hidden_name(p->name()))
- n = p->name();
- else
- {
- n = ".";
- std::string pkgpath = Gogo::hidden_name_pkgpath(p->name());
- n.append(Gogo::pkgpath_for_symbol(pkgpath));
- n.append(1, '.');
- n.append(Gogo::unpack_hidden_name(p->name()));
- }
- char buf[20];
- snprintf(buf, sizeof buf, "%u_",
- static_cast<unsigned int>(n.length()));
- ret->append(buf);
- ret->append(n);
- }
- this->append_mangled_name(p->type(), gogo, ret);
- }
- this->seen_ = false;
- }
-
- ret->push_back('e');
-}
-
-// Export.
-
-void
-Interface_type::do_export(Export* exp) const
-{
- exp->write_c_string("interface { ");
-
- const Typed_identifier_list* methods = this->parse_methods_;
- if (methods != NULL)
- {
- for (Typed_identifier_list::const_iterator pm = methods->begin();
- pm != methods->end();
- ++pm)
- {
- if (pm->name().empty())
- {
- exp->write_c_string("? ");
- exp->write_type(pm->type());
- }
- else
- {
- exp->write_string(pm->name());
- exp->write_c_string(" (");
-
- const Function_type* fntype = pm->type()->function_type();
-
- bool first = true;
- const Typed_identifier_list* parameters = fntype->parameters();
- if (parameters != NULL)
- {
- bool is_varargs = fntype->is_varargs();
- for (Typed_identifier_list::const_iterator pp =
- parameters->begin();
- pp != parameters->end();
- ++pp)
- {
- if (first)
- first = false;
- else
- exp->write_c_string(", ");
- exp->write_name(pp->name());
- exp->write_c_string(" ");
- if (!is_varargs || pp + 1 != parameters->end())
- exp->write_type(pp->type());
- else
- {
- exp->write_c_string("...");
- Type *pptype = pp->type();
- exp->write_type(pptype->array_type()->element_type());
- }
- }
- }
-
- exp->write_c_string(")");
-
- const Typed_identifier_list* results = fntype->results();
- if (results != NULL)
- {
- exp->write_c_string(" ");
- if (results->size() == 1 && results->begin()->name().empty())
- exp->write_type(results->begin()->type());
- else
- {
- first = true;
- exp->write_c_string("(");
- for (Typed_identifier_list::const_iterator p =
- results->begin();
- p != results->end();
- ++p)
- {
- if (first)
- first = false;
- else
- exp->write_c_string(", ");
- exp->write_name(p->name());
- exp->write_c_string(" ");
- exp->write_type(p->type());
- }
- exp->write_c_string(")");
- }
- }
- }
-
- exp->write_c_string("; ");
- }
- }
-
- exp->write_c_string("}");
-}
-
-// Import an interface type.
-
-Interface_type*
-Interface_type::do_import(Import* imp)
-{
- imp->require_c_string("interface { ");
-
- Typed_identifier_list* methods = new Typed_identifier_list;
- while (imp->peek_char() != '}')
- {
- std::string name = imp->read_identifier();
-
- if (name == "?")
- {
- imp->require_c_string(" ");
- Type* t = imp->read_type();
- methods->push_back(Typed_identifier("", t, imp->location()));
- imp->require_c_string("; ");
- continue;
- }
-
- imp->require_c_string(" (");
-
- Typed_identifier_list* parameters;
- bool is_varargs = false;
- if (imp->peek_char() == ')')
- parameters = NULL;
- else
- {
- parameters = new Typed_identifier_list;
- while (true)
- {
- std::string name = imp->read_name();
- imp->require_c_string(" ");
-
- if (imp->match_c_string("..."))
- {
- imp->advance(3);
- is_varargs = true;
- }
-
- Type* ptype = imp->read_type();
- if (is_varargs)
- ptype = Type::make_array_type(ptype, NULL);
- parameters->push_back(Typed_identifier(name, ptype,
- imp->location()));
- if (imp->peek_char() != ',')
- break;
- go_assert(!is_varargs);
- imp->require_c_string(", ");
- }
- }
- imp->require_c_string(")");
-
- Typed_identifier_list* results;
- if (imp->peek_char() != ' ')
- results = NULL;
- else
- {
- results = new Typed_identifier_list;
- imp->advance(1);
- if (imp->peek_char() != '(')
- {
- Type* rtype = imp->read_type();
- results->push_back(Typed_identifier("", rtype, imp->location()));
- }
- else
- {
- imp->advance(1);
- while (true)
- {
- std::string name = imp->read_name();
- imp->require_c_string(" ");
- Type* rtype = imp->read_type();
- results->push_back(Typed_identifier(name, rtype,
- imp->location()));
- if (imp->peek_char() != ',')
- break;
- imp->require_c_string(", ");
- }
- imp->require_c_string(")");
- }
- }
-
- Function_type* fntype = Type::make_function_type(NULL, parameters,
- results,
- imp->location());
- if (is_varargs)
- fntype->set_is_varargs();
- methods->push_back(Typed_identifier(name, fntype, imp->location()));
-
- imp->require_c_string("; ");
- }
-
- imp->require_c_string("}");
-
- if (methods->empty())
- {
- delete methods;
- methods = NULL;
- }
-
- return Type::make_interface_type(methods, imp->location());
-}
-
-// Make an interface type.
-
-Interface_type*
-Type::make_interface_type(Typed_identifier_list* methods,
- Location location)
-{
- return new Interface_type(methods, location);
-}
-
-// Make an empty interface type.
-
-Interface_type*
-Type::make_empty_interface_type(Location location)
-{
- Interface_type* ret = new Interface_type(NULL, location);
- ret->finalize_methods();
- return ret;
-}
-
-// Class Method.
-
-// Bind a method to an object.
-
-Expression*
-Method::bind_method(Expression* expr, Location location) const
-{
- if (this->stub_ == NULL)
- {
- // When there is no stub object, the binding is determined by
- // the child class.
- return this->do_bind_method(expr, location);
- }
- return Expression::make_bound_method(expr, this->stub_, location);
-}
-
-// Return the named object associated with a method. This may only be
-// called after methods are finalized.
-
-Named_object*
-Method::named_object() const
-{
- if (this->stub_ != NULL)
- return this->stub_;
- return this->do_named_object();
-}
-
-// Class Named_method.
-
-// The type of the method.
-
-Function_type*
-Named_method::do_type() const
-{
- if (this->named_object_->is_function())
- return this->named_object_->func_value()->type();
- else if (this->named_object_->is_function_declaration())
- return this->named_object_->func_declaration_value()->type();
- else
- go_unreachable();
-}
-
-// Return the location of the method receiver.
-
-Location
-Named_method::do_receiver_location() const
-{
- return this->do_type()->receiver()->location();
-}
-
-// Bind a method to an object.
-
-Expression*
-Named_method::do_bind_method(Expression* expr, Location location) const
-{
- Named_object* no = this->named_object_;
- Bound_method_expression* bme = Expression::make_bound_method(expr, no,
- location);
- // If this is not a local method, and it does not use a stub, then
- // the real method expects a different type. We need to cast the
- // first argument.
- if (this->depth() > 0 && !this->needs_stub_method())
- {
- Function_type* ftype = this->do_type();
- go_assert(ftype->is_method());
- Type* frtype = ftype->receiver()->type();
- bme->set_first_argument_type(frtype);
- }
- return bme;
-}
-
-// Return whether this method should not participate in interfaces.
-
-bool
-Named_method::do_nointerface() const
-{
- Named_object* no = this->named_object_;
- return no->is_function() && no->func_value()->nointerface();
-}
-
-// Class Interface_method.
-
-// Bind a method to an object.
-
-Expression*
-Interface_method::do_bind_method(Expression* expr,
- Location location) const
-{
- return Expression::make_interface_field_reference(expr, this->name_,
- location);
-}
-
-// Class Methods.
-
-// Insert a new method. Return true if it was inserted, false
-// otherwise.
-
-bool
-Methods::insert(const std::string& name, Method* m)
-{
- std::pair<Method_map::iterator, bool> ins =
- this->methods_.insert(std::make_pair(name, m));
- if (ins.second)
- return true;
- else
- {
- Method* old_method = ins.first->second;
- if (m->depth() < old_method->depth())
- {
- delete old_method;
- ins.first->second = m;
- return true;
- }
- else
- {
- if (m->depth() == old_method->depth())
- old_method->set_is_ambiguous();
- return false;
- }
- }
-}
-
-// Return the number of unambiguous methods.
-
-size_t
-Methods::count() const
-{
- size_t ret = 0;
- for (Method_map::const_iterator p = this->methods_.begin();
- p != this->methods_.end();
- ++p)
- if (!p->second->is_ambiguous())
- ++ret;
- return ret;
-}
-
-// Class Named_type.
-
-// Return the name of the type.
-
-const std::string&
-Named_type::name() const
-{
- return this->named_object_->name();
-}
-
-// Return the name of the type to use in an error message.
-
-std::string
-Named_type::message_name() const
-{
- return this->named_object_->message_name();
-}
-
-// Whether this is an alias. There are currently only two aliases so
-// we just recognize them by name.
-
-bool
-Named_type::is_alias() const
-{
- if (!this->is_builtin())
- return false;
- const std::string& name(this->name());
- return name == "byte" || name == "rune";
-}
-
-// Return the base type for this type. We have to be careful about
-// circular type definitions, which are invalid but may be seen here.
-
-Type*
-Named_type::named_base()
-{
- if (this->seen_)
- return this;
- this->seen_ = true;
- Type* ret = this->type_->base();
- this->seen_ = false;
- return ret;
-}
-
-const Type*
-Named_type::named_base() const
-{
- if (this->seen_)
- return this;
- this->seen_ = true;
- const Type* ret = this->type_->base();
- this->seen_ = false;
- return ret;
-}
-
-// Return whether this is an error type. We have to be careful about
-// circular type definitions, which are invalid but may be seen here.
-
-bool
-Named_type::is_named_error_type() const
-{
- if (this->seen_)
- return false;
- this->seen_ = true;
- bool ret = this->type_->is_error_type();
- this->seen_ = false;
- return ret;
-}
-
-// Whether this type is comparable. We have to be careful about
-// circular type definitions.
-
-bool
-Named_type::named_type_is_comparable(std::string* reason) const
-{
- if (this->seen_)
- return false;
- this->seen_ = true;
- bool ret = Type::are_compatible_for_comparison(true, this->type_,
- this->type_, reason);
- this->seen_ = false;
- return ret;
-}
-
-// Add a method to this type.
-
-Named_object*
-Named_type::add_method(const std::string& name, Function* function)
-{
- if (this->local_methods_ == NULL)
- this->local_methods_ = new Bindings(NULL);
- return this->local_methods_->add_function(name, NULL, function);
-}
-
-// Add a method declaration to this type.
-
-Named_object*
-Named_type::add_method_declaration(const std::string& name, Package* package,
- Function_type* type,
- Location location)
-{
- if (this->local_methods_ == NULL)
- this->local_methods_ = new Bindings(NULL);
- return this->local_methods_->add_function_declaration(name, package, type,
- location);
-}
-
-// Add an existing method to this type.
-
-void
-Named_type::add_existing_method(Named_object* no)
-{
- if (this->local_methods_ == NULL)
- this->local_methods_ = new Bindings(NULL);
- this->local_methods_->add_named_object(no);
-}
-
-// Look for a local method NAME, and returns its named object, or NULL
-// if not there.
-
-Named_object*
-Named_type::find_local_method(const std::string& name) const
-{
- if (this->local_methods_ == NULL)
- return NULL;
- return this->local_methods_->lookup(name);
-}
-
-// Return whether NAME is an unexported field or method, for better
-// error reporting.
-
-bool
-Named_type::is_unexported_local_method(Gogo* gogo,
- const std::string& name) const
-{
- Bindings* methods = this->local_methods_;
- if (methods != NULL)
- {
- for (Bindings::const_declarations_iterator p =
- methods->begin_declarations();
- p != methods->end_declarations();
- ++p)
- {
- if (Gogo::is_hidden_name(p->first)
- && name == Gogo::unpack_hidden_name(p->first)
- && gogo->pack_hidden_name(name, false) != p->first)
- return true;
- }
- }
- return false;
-}
-
-// Build the complete list of methods for this type, which means
-// recursively including all methods for anonymous fields. Create all
-// stub methods.
-
-void
-Named_type::finalize_methods(Gogo* gogo)
-{
- if (this->all_methods_ != NULL)
- return;
-
- if (this->local_methods_ != NULL
- && (this->points_to() != NULL || this->interface_type() != NULL))
- {
- const Bindings* lm = this->local_methods_;
- for (Bindings::const_declarations_iterator p = lm->begin_declarations();
- p != lm->end_declarations();
- ++p)
- error_at(p->second->location(),
- "invalid pointer or interface receiver type");
- delete this->local_methods_;
- this->local_methods_ = NULL;
- return;
- }
-
- Type::finalize_methods(gogo, this, this->location_, &this->all_methods_);
-}
-
-// Return the method NAME, or NULL if there isn't one or if it is
-// ambiguous. Set *IS_AMBIGUOUS if the method exists but is
-// ambiguous.
-
-Method*
-Named_type::method_function(const std::string& name, bool* is_ambiguous) const
-{
- return Type::method_function(this->all_methods_, name, is_ambiguous);
-}
-
-// Return a pointer to the interface method table for this type for
-// the interface INTERFACE. IS_POINTER is true if this is for a
-// pointer to THIS.
-
-tree
-Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface,
- bool is_pointer)
-{
- return Type::interface_method_table(gogo, this, interface, is_pointer,
- &this->interface_method_tables_,
- &this->pointer_interface_method_tables_);
-}
-
-// Return whether a named type has any hidden fields.
-
-bool
-Named_type::named_type_has_hidden_fields(std::string* reason) const
-{
- if (this->seen_)
- return false;
- this->seen_ = true;
- bool ret = this->type_->has_hidden_fields(this, reason);
- this->seen_ = false;
- return ret;
-}
-
-// Look for a use of a complete type within another type. This is
-// used to check that we don't try to use a type within itself.
-
-class Find_type_use : public Traverse
-{
- public:
- Find_type_use(Named_type* find_type)
- : Traverse(traverse_types),
- find_type_(find_type), found_(false)
- { }
-
- // Whether we found the type.
- bool
- found() const
- { return this->found_; }
-
- protected:
- int
- type(Type*);
-
- private:
- // The type we are looking for.
- Named_type* find_type_;
- // Whether we found the type.
- bool found_;
-};
-
-// Check for FIND_TYPE in TYPE.
-
-int
-Find_type_use::type(Type* type)
-{
- if (type->named_type() != NULL && this->find_type_ == type->named_type())
- {
- this->found_ = true;
- return TRAVERSE_EXIT;
- }
-
- // It's OK if we see a reference to the type in any type which is
- // essentially a pointer: a pointer, a slice, a function, a map, or
- // a channel.
- if (type->points_to() != NULL
- || type->is_slice_type()
- || type->function_type() != NULL
- || type->map_type() != NULL
- || type->channel_type() != NULL)
- return TRAVERSE_SKIP_COMPONENTS;
-
- // For an interface, a reference to the type in a method type should
- // be ignored, but we have to consider direct inheritance. When
- // this is called, there may be cases of direct inheritance
- // represented as a method with no name.
- if (type->interface_type() != NULL)
- {
- const Typed_identifier_list* methods = type->interface_type()->methods();
- if (methods != NULL)
- {
- for (Typed_identifier_list::const_iterator p = methods->begin();
- p != methods->end();
- ++p)
- {
- if (p->name().empty())
- {
- if (Type::traverse(p->type(), this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- }
- return TRAVERSE_SKIP_COMPONENTS;
- }
-
- // Otherwise, FIND_TYPE_ depends on TYPE, in the sense that we need
- // to convert TYPE to the backend representation before we convert
- // FIND_TYPE_.
- if (type->named_type() != NULL)
- {
- switch (type->base()->classification())
- {
- case Type::TYPE_ERROR:
- case Type::TYPE_BOOLEAN:
- case Type::TYPE_INTEGER:
- case Type::TYPE_FLOAT:
- case Type::TYPE_COMPLEX:
- case Type::TYPE_STRING:
- case Type::TYPE_NIL:
- break;
-
- case Type::TYPE_ARRAY:
- case Type::TYPE_STRUCT:
- this->find_type_->add_dependency(type->named_type());
- break;
-
- case Type::TYPE_NAMED:
- case Type::TYPE_FORWARD:
- go_assert(saw_errors());
- break;
-
- case Type::TYPE_VOID:
- case Type::TYPE_SINK:
- case Type::TYPE_FUNCTION:
- case Type::TYPE_POINTER:
- case Type::TYPE_CALL_MULTIPLE_RESULT:
- case Type::TYPE_MAP:
- case Type::TYPE_CHANNEL:
- case Type::TYPE_INTERFACE:
- default:
- go_unreachable();
- }
- }
-
- return TRAVERSE_CONTINUE;
-}
-
-// Verify that a named type does not refer to itself.
-
-bool
-Named_type::do_verify()
-{
- if (this->is_verified_)
- return true;
- this->is_verified_ = true;
-
- Find_type_use find(this);
- Type::traverse(this->type_, &find);
- if (find.found())
- {
- error_at(this->location_, "invalid recursive type %qs",
- this->message_name().c_str());
- this->is_error_ = true;
- return false;
- }
-
- // Check whether any of the local methods overloads an existing
- // struct field or interface method. We don't need to check the
- // list of methods against itself: that is handled by the Bindings
- // code.
- if (this->local_methods_ != NULL)
- {
- Struct_type* st = this->type_->struct_type();
- if (st != NULL)
- {
- for (Bindings::const_declarations_iterator p =
- this->local_methods_->begin_declarations();
- p != this->local_methods_->end_declarations();
- ++p)
- {
- const std::string& name(p->first);
- if (st != NULL && st->find_local_field(name, NULL) != NULL)
- {
- error_at(p->second->location(),
- "method %qs redeclares struct field name",
- Gogo::message_name(name).c_str());
- }
- }
- }
- }
-
- return true;
-}
-
-// Return whether this type is or contains a pointer.
-
-bool
-Named_type::do_has_pointer() const
-{
- if (this->seen_)
- return false;
- this->seen_ = true;
- bool ret = this->type_->has_pointer();
- this->seen_ = false;
- return ret;
-}
-
-// Return whether comparisons for this type can use the identity
-// function.
-
-bool
-Named_type::do_compare_is_identity(Gogo* gogo)
-{
- // We don't use this->seen_ here because compare_is_identity may
- // call base() later, and that will mess up if seen_ is set here.
- if (this->seen_in_compare_is_identity_)
- return false;
- this->seen_in_compare_is_identity_ = true;
- bool ret = this->type_->compare_is_identity(gogo);
- this->seen_in_compare_is_identity_ = false;
- return ret;
-}
-
-// Return a hash code. This is used for method lookup. We simply
-// hash on the name itself.
-
-unsigned int
-Named_type::do_hash_for_method(Gogo* gogo) const
-{
- if (this->is_alias())
- return this->type_->named_type()->do_hash_for_method(gogo);
-
- const std::string& name(this->named_object()->name());
- unsigned int ret = Type::hash_string(name, 0);
-
- // GOGO will be NULL here when called from Type_hash_identical.
- // That is OK because that is only used for internal hash tables
- // where we are going to be comparing named types for equality. In
- // other cases, which are cases where the runtime is going to
- // compare hash codes to see if the types are the same, we need to
- // include the pkgpath in the hash.
- if (gogo != NULL && !Gogo::is_hidden_name(name) && !this->is_builtin())
- {
- const Package* package = this->named_object()->package();
- if (package == NULL)
- ret = Type::hash_string(gogo->pkgpath(), ret);
- else
- ret = Type::hash_string(package->pkgpath(), ret);
- }
-
- return ret;
-}
-
-// Convert a named type to the backend representation. In order to
-// get dependencies right, we fill in a dummy structure for this type,
-// then convert all the dependencies, then complete this type. When
-// this function is complete, the size of the type is known.
-
-void
-Named_type::convert(Gogo* gogo)
-{
- if (this->is_error_ || this->is_converted_)
- return;
-
- this->create_placeholder(gogo);
-
- // If we are called to turn unsafe.Sizeof into a constant, we may
- // not have verified the type yet. We have to make sure it is
- // verified, since that sets the list of dependencies.
- this->verify();
-
- // Convert all the dependencies. If they refer indirectly back to
- // this type, they will pick up the intermediate tree we just
- // created.
- for (std::vector<Named_type*>::const_iterator p = this->dependencies_.begin();
- p != this->dependencies_.end();
- ++p)
- (*p)->convert(gogo);
-
- // Complete this type.
- Btype* bt = this->named_btype_;
- Type* base = this->type_->base();
- switch (base->classification())
- {
- case TYPE_VOID:
- case TYPE_BOOLEAN:
- case TYPE_INTEGER:
- case TYPE_FLOAT:
- case TYPE_COMPLEX:
- case TYPE_STRING:
- case TYPE_NIL:
- break;
-
- case TYPE_MAP:
- case TYPE_CHANNEL:
- break;
-
- case TYPE_FUNCTION:
- case TYPE_POINTER:
- // The size of these types is already correct. We don't worry
- // about filling them in until later, when we also track
- // circular references.
- break;
-
- case TYPE_STRUCT:
- {
- std::vector<Backend::Btyped_identifier> bfields;
- get_backend_struct_fields(gogo, base->struct_type()->fields(),
- true, &bfields);
- if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
- bt = gogo->backend()->error_type();
- }
- break;
-
- case TYPE_ARRAY:
- // Slice types were completed in create_placeholder.
- if (!base->is_slice_type())
- {
- Btype* bet = base->array_type()->get_backend_element(gogo, true);
- Bexpression* blen = base->array_type()->get_backend_length(gogo);
- if (!gogo->backend()->set_placeholder_array_type(bt, bet, blen))
- bt = gogo->backend()->error_type();
- }
- break;
-
- case TYPE_INTERFACE:
- // Interface types were completed in create_placeholder.
- break;
-
- case TYPE_ERROR:
- return;
-
- default:
- case TYPE_SINK:
- case TYPE_CALL_MULTIPLE_RESULT:
- case TYPE_NAMED:
- case TYPE_FORWARD:
- go_unreachable();
- }
-
- this->named_btype_ = bt;
- this->is_converted_ = true;
- this->is_placeholder_ = false;
-}
-
-// Create the placeholder for a named type. This is the first step in
-// converting to the backend representation.
-
-void
-Named_type::create_placeholder(Gogo* gogo)
-{
- if (this->is_error_)
- this->named_btype_ = gogo->backend()->error_type();
-
- if (this->named_btype_ != NULL)
- return;
-
- // Create the structure for this type. Note that because we call
- // base() here, we don't attempt to represent a named type defined
- // as another named type. Instead both named types will point to
- // different base representations.
- Type* base = this->type_->base();
- Btype* bt;
- bool set_name = true;
- switch (base->classification())
- {
- case TYPE_ERROR:
- this->is_error_ = true;
- this->named_btype_ = gogo->backend()->error_type();
- return;
-
- case TYPE_VOID:
- case TYPE_BOOLEAN:
- case TYPE_INTEGER:
- case TYPE_FLOAT:
- case TYPE_COMPLEX:
- case TYPE_STRING:
- case TYPE_NIL:
- // These are simple basic types, we can just create them
- // directly.
- bt = Type::get_named_base_btype(gogo, base);
- break;
-
- case TYPE_MAP:
- case TYPE_CHANNEL:
- // All maps and channels have the same backend representation.
- bt = Type::get_named_base_btype(gogo, base);
- break;
-
- case TYPE_FUNCTION:
- case TYPE_POINTER:
- {
- bool for_function = base->classification() == TYPE_FUNCTION;
- bt = gogo->backend()->placeholder_pointer_type(this->name(),
- this->location_,
- for_function);
- set_name = false;
- }
- break;
-
- case TYPE_STRUCT:
- bt = gogo->backend()->placeholder_struct_type(this->name(),
- this->location_);
- this->is_placeholder_ = true;
- set_name = false;
- break;
-
- case TYPE_ARRAY:
- if (base->is_slice_type())
- bt = gogo->backend()->placeholder_struct_type(this->name(),
- this->location_);
- else
- {
- bt = gogo->backend()->placeholder_array_type(this->name(),
- this->location_);
- this->is_placeholder_ = true;
- }
- set_name = false;
- break;
-
- case TYPE_INTERFACE:
- if (base->interface_type()->is_empty())
- bt = Interface_type::get_backend_empty_interface_type(gogo);
- else
- {
- bt = gogo->backend()->placeholder_struct_type(this->name(),
- this->location_);
- set_name = false;
- }
- break;
-
- default:
- case TYPE_SINK:
- case TYPE_CALL_MULTIPLE_RESULT:
- case TYPE_NAMED:
- case TYPE_FORWARD:
- go_unreachable();
- }
-
- if (set_name)
- bt = gogo->backend()->named_type(this->name(), bt, this->location_);
-
- this->named_btype_ = bt;
-
- if (base->is_slice_type())
- {
- // We do not record slices as dependencies of other types,
- // because we can fill them in completely here with the final
- // size.
- std::vector<Backend::Btyped_identifier> bfields;
- get_backend_slice_fields(gogo, base->array_type(), true, &bfields);
- if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
- this->named_btype_ = gogo->backend()->error_type();
- }
- else if (base->interface_type() != NULL
- && !base->interface_type()->is_empty())
- {
- // We do not record interfaces as dependencies of other types,
- // because we can fill them in completely here with the final
- // size.
- std::vector<Backend::Btyped_identifier> bfields;
- get_backend_interface_fields(gogo, base->interface_type(), true,
- &bfields);
- if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
- this->named_btype_ = gogo->backend()->error_type();
- }
-}
-
-// Get a tree for a named type.
-
-Btype*
-Named_type::do_get_backend(Gogo* gogo)
-{
- if (this->is_error_)
- return gogo->backend()->error_type();
-
- Btype* bt = this->named_btype_;
-
- if (!gogo->named_types_are_converted())
- {
- // We have not completed converting named types. NAMED_BTYPE_
- // is a placeholder and we shouldn't do anything further.
- if (bt != NULL)
- return bt;
-
- // We don't build dependencies for types whose sizes do not
- // change or are not relevant, so we may see them here while
- // converting types.
- this->create_placeholder(gogo);
- bt = this->named_btype_;
- go_assert(bt != NULL);
- return bt;
- }
-
- // We are not converting types. This should only be called if the
- // type has already been converted.
- if (!this->is_converted_)
- {
- go_assert(saw_errors());
- return gogo->backend()->error_type();
- }
-
- go_assert(bt != NULL);
-
- // Complete the tree.
- Type* base = this->type_->base();
- Btype* bt1;
- switch (base->classification())
- {
- case TYPE_ERROR:
- return gogo->backend()->error_type();
-
- case TYPE_VOID:
- case TYPE_BOOLEAN:
- case TYPE_INTEGER:
- case TYPE_FLOAT:
- case TYPE_COMPLEX:
- case TYPE_STRING:
- case TYPE_NIL:
- case TYPE_MAP:
- case TYPE_CHANNEL:
- return bt;
-
- case TYPE_STRUCT:
- if (!this->seen_in_get_backend_)
- {
- this->seen_in_get_backend_ = true;
- base->struct_type()->finish_backend_fields(gogo);
- this->seen_in_get_backend_ = false;
- }
- return bt;
-
- case TYPE_ARRAY:
- if (!this->seen_in_get_backend_)
- {
- this->seen_in_get_backend_ = true;
- base->array_type()->finish_backend_element(gogo);
- this->seen_in_get_backend_ = false;
- }
- return bt;
-
- case TYPE_INTERFACE:
- if (!this->seen_in_get_backend_)
- {
- this->seen_in_get_backend_ = true;
- base->interface_type()->finish_backend_methods(gogo);
- this->seen_in_get_backend_ = false;
- }
- return bt;
-
- case TYPE_FUNCTION:
- // Don't build a circular data structure. GENERIC can't handle
- // it.
- if (this->seen_in_get_backend_)
- {
- this->is_circular_ = true;
- return gogo->backend()->circular_pointer_type(bt, true);
- }
- this->seen_in_get_backend_ = true;
- bt1 = Type::get_named_base_btype(gogo, base);
- this->seen_in_get_backend_ = false;
- if (this->is_circular_)
- bt1 = gogo->backend()->circular_pointer_type(bt, true);
- if (!gogo->backend()->set_placeholder_function_type(bt, bt1))
- bt = gogo->backend()->error_type();
- return bt;
-
- case TYPE_POINTER:
- // Don't build a circular data structure. GENERIC can't handle
- // it.
- if (this->seen_in_get_backend_)
- {
- this->is_circular_ = true;
- return gogo->backend()->circular_pointer_type(bt, false);
- }
- this->seen_in_get_backend_ = true;
- bt1 = Type::get_named_base_btype(gogo, base);
- this->seen_in_get_backend_ = false;
- if (this->is_circular_)
- bt1 = gogo->backend()->circular_pointer_type(bt, false);
- if (!gogo->backend()->set_placeholder_pointer_type(bt, bt1))
- bt = gogo->backend()->error_type();
- return bt;
-
- default:
- case TYPE_SINK:
- case TYPE_CALL_MULTIPLE_RESULT:
- case TYPE_NAMED:
- case TYPE_FORWARD:
- go_unreachable();
- }
-
- go_unreachable();
-}
-
-// Build a type descriptor for a named type.
-
-Expression*
-Named_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- if (name == NULL && this->is_alias())
- return this->type_->type_descriptor(gogo, this->type_);
-
- // If NAME is not NULL, then we don't really want the type
- // descriptor for this type; we want the descriptor for the
- // underlying type, giving it the name NAME.
- return this->named_type_descriptor(gogo, this->type_,
- name == NULL ? this : name);
-}
-
-// Add to the reflection string. This is used mostly for the name of
-// the type used in a type descriptor, not for actual reflection
-// strings.
-
-void
-Named_type::do_reflection(Gogo* gogo, std::string* ret) const
-{
- if (this->is_alias())
- {
- this->append_reflection(this->type_, gogo, ret);
- return;
- }
- if (!this->is_builtin())
- {
- // We handle -fgo-prefix and -fgo-pkgpath differently here for
- // compatibility with how the compiler worked before
- // -fgo-pkgpath was introduced. When -fgo-pkgpath is specified,
- // we use it to make a unique reflection string, so that the
- // type canonicalization in the reflect package will work. In
- // order to be compatible with the gc compiler, we put tabs into
- // the package path, so that the reflect methods can discard it.
- const Package* package = this->named_object_->package();
- if (gogo->pkgpath_from_option())
- {
- ret->push_back('\t');
- ret->append(package != NULL
- ? package->pkgpath_symbol()
- : gogo->pkgpath_symbol());
- ret->push_back('\t');
- }
- ret->append(package != NULL
- ? package->package_name()
- : gogo->package_name());
- ret->push_back('.');
- }
- if (this->in_function_ != NULL)
- {
- ret->push_back('\t');
- ret->append(Gogo::unpack_hidden_name(this->in_function_->name()));
- ret->push_back('$');
- if (this->in_function_index_ > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", this->in_function_index_);
- ret->append(buf);
- ret->push_back('$');
- }
- ret->push_back('\t');
- }
- ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
-}
-
-// Get the mangled name.
-
-void
-Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- if (this->is_alias())
- {
- this->append_mangled_name(this->type_, gogo, ret);
- return;
- }
- Named_object* no = this->named_object_;
- std::string name;
- if (this->is_builtin())
- go_assert(this->in_function_ == NULL);
- else
- {
- const std::string& pkgpath(no->package() == NULL
- ? gogo->pkgpath_symbol()
- : no->package()->pkgpath_symbol());
- name = pkgpath;
- name.append(1, '.');
- if (this->in_function_ != NULL)
- {
- name.append(Gogo::unpack_hidden_name(this->in_function_->name()));
- name.append(1, '$');
- if (this->in_function_index_ > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", this->in_function_index_);
- name.append(buf);
- name.append(1, '$');
- }
- }
- }
- name.append(Gogo::unpack_hidden_name(no->name()));
- char buf[20];
- snprintf(buf, sizeof buf, "N%u_", static_cast<unsigned int>(name.length()));
- ret->append(buf);
- ret->append(name);
-}
-
-// Export the type. This is called to export a global type.
-
-void
-Named_type::export_named_type(Export* exp, const std::string&) const
-{
- // We don't need to write the name of the type here, because it will
- // be written by Export::write_type anyhow.
- exp->write_c_string("type ");
- exp->write_type(this);
- exp->write_c_string(";\n");
-}
-
-// Import a named type.
-
-void
-Named_type::import_named_type(Import* imp, Named_type** ptype)
-{
- imp->require_c_string("type ");
- Type *type = imp->read_type();
- *ptype = type->named_type();
- go_assert(*ptype != NULL);
- imp->require_c_string(";\n");
-}
-
-// Export the type when it is referenced by another type. In this
-// case Export::export_type will already have issued the name.
-
-void
-Named_type::do_export(Export* exp) const
-{
- exp->write_type(this->type_);
-
- // To save space, we only export the methods directly attached to
- // this type.
- Bindings* methods = this->local_methods_;
- if (methods == NULL)
- return;
-
- exp->write_c_string("\n");
- for (Bindings::const_definitions_iterator p = methods->begin_definitions();
- p != methods->end_definitions();
- ++p)
- {
- exp->write_c_string(" ");
- (*p)->export_named_object(exp);
- }
-
- for (Bindings::const_declarations_iterator p = methods->begin_declarations();
- p != methods->end_declarations();
- ++p)
- {
- if (p->second->is_function_declaration())
- {
- exp->write_c_string(" ");
- p->second->export_named_object(exp);
- }
- }
-}
-
-// Make a named type.
-
-Named_type*
-Type::make_named_type(Named_object* named_object, Type* type,
- Location location)
-{
- return new Named_type(named_object, type, location);
-}
-
-// Finalize the methods for TYPE. It will be a named type or a struct
-// type. This sets *ALL_METHODS to the list of methods, and builds
-// all required stubs.
-
-void
-Type::finalize_methods(Gogo* gogo, const Type* type, Location location,
- Methods** all_methods)
-{
- *all_methods = NULL;
- Types_seen types_seen;
- Type::add_methods_for_type(type, NULL, 0, false, false, &types_seen,
- all_methods);
- Type::build_stub_methods(gogo, type, *all_methods, location);
-}
-
-// Add the methods for TYPE to *METHODS. FIELD_INDEXES is used to
-// build up the struct field indexes as we go. DEPTH is the depth of
-// the field within TYPE. IS_EMBEDDED_POINTER is true if we are
-// adding these methods for an anonymous field with pointer type.
-// NEEDS_STUB_METHOD is true if we need to use a stub method which
-// calls the real method. TYPES_SEEN is used to avoid infinite
-// recursion.
-
-void
-Type::add_methods_for_type(const Type* type,
- const Method::Field_indexes* field_indexes,
- unsigned int depth,
- bool is_embedded_pointer,
- bool needs_stub_method,
- Types_seen* types_seen,
- Methods** methods)
-{
- // Pointer types may not have methods.
- if (type->points_to() != NULL)
- return;
-
- const Named_type* nt = type->named_type();
- if (nt != NULL)
- {
- std::pair<Types_seen::iterator, bool> ins = types_seen->insert(nt);
- if (!ins.second)
- return;
- }
-
- if (nt != NULL)
- Type::add_local_methods_for_type(nt, field_indexes, depth,
- is_embedded_pointer, needs_stub_method,
- methods);
-
- Type::add_embedded_methods_for_type(type, field_indexes, depth,
- is_embedded_pointer, needs_stub_method,
- types_seen, methods);
-
- // If we are called with depth > 0, then we are looking at an
- // anonymous field of a struct. If such a field has interface type,
- // then we need to add the interface methods. We don't want to add
- // them when depth == 0, because we will already handle them
- // following the usual rules for an interface type.
- if (depth > 0)
- Type::add_interface_methods_for_type(type, field_indexes, depth, methods);
-}
-
-// Add the local methods for the named type NT to *METHODS. The
-// parameters are as for add_methods_to_type.
-
-void
-Type::add_local_methods_for_type(const Named_type* nt,
- const Method::Field_indexes* field_indexes,
- unsigned int depth,
- bool is_embedded_pointer,
- bool needs_stub_method,
- Methods** methods)
-{
- const Bindings* local_methods = nt->local_methods();
- if (local_methods == NULL)
- return;
-
- if (*methods == NULL)
- *methods = new Methods();
-
- for (Bindings::const_declarations_iterator p =
- local_methods->begin_declarations();
- p != local_methods->end_declarations();
- ++p)
- {
- Named_object* no = p->second;
- bool is_value_method = (is_embedded_pointer
- || !Type::method_expects_pointer(no));
- Method* m = new Named_method(no, field_indexes, depth, is_value_method,
- (needs_stub_method
- || (depth > 0 && is_value_method)));
- if (!(*methods)->insert(no->name(), m))
- delete m;
- }
-}
-
-// Add the embedded methods for TYPE to *METHODS. These are the
-// methods attached to anonymous fields. The parameters are as for
-// add_methods_to_type.
-
-void
-Type::add_embedded_methods_for_type(const Type* type,
- const Method::Field_indexes* field_indexes,
- unsigned int depth,
- bool is_embedded_pointer,
- bool needs_stub_method,
- Types_seen* types_seen,
- Methods** methods)
-{
- // Look for anonymous fields in TYPE. TYPE has fields if it is a
- // struct.
- const Struct_type* st = type->struct_type();
- if (st == NULL)
- return;
-
- const Struct_field_list* fields = st->fields();
- if (fields == NULL)
- return;
-
- unsigned int i = 0;
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf, ++i)
- {
- if (!pf->is_anonymous())
- continue;
-
- Type* ftype = pf->type();
- bool is_pointer = false;
- if (ftype->points_to() != NULL)
- {
- ftype = ftype->points_to();
- is_pointer = true;
- }
- Named_type* fnt = ftype->named_type();
- if (fnt == NULL)
- {
- // This is an error, but it will be diagnosed elsewhere.
- continue;
- }
-
- Method::Field_indexes* sub_field_indexes = new Method::Field_indexes();
- sub_field_indexes->next = field_indexes;
- sub_field_indexes->field_index = i;
-
- Type::add_methods_for_type(fnt, sub_field_indexes, depth + 1,
- (is_embedded_pointer || is_pointer),
- (needs_stub_method
- || is_pointer
- || i > 0),
- types_seen,
- methods);
- }
-}
-
-// If TYPE is an interface type, then add its method to *METHODS.
-// This is for interface methods attached to an anonymous field. The
-// parameters are as for add_methods_for_type.
-
-void
-Type::add_interface_methods_for_type(const Type* type,
- const Method::Field_indexes* field_indexes,
- unsigned int depth,
- Methods** methods)
-{
- const Interface_type* it = type->interface_type();
- if (it == NULL)
- return;
-
- const Typed_identifier_list* imethods = it->methods();
- if (imethods == NULL)
- return;
-
- if (*methods == NULL)
- *methods = new Methods();
-
- for (Typed_identifier_list::const_iterator pm = imethods->begin();
- pm != imethods->end();
- ++pm)
- {
- Function_type* fntype = pm->type()->function_type();
- if (fntype == NULL)
- {
- // This is an error, but it should be reported elsewhere
- // when we look at the methods for IT.
- continue;
- }
- go_assert(!fntype->is_method());
- fntype = fntype->copy_with_receiver(const_cast<Type*>(type));
- Method* m = new Interface_method(pm->name(), pm->location(), fntype,
- field_indexes, depth);
- if (!(*methods)->insert(pm->name(), m))
- delete m;
- }
-}
-
-// Build stub methods for TYPE as needed. METHODS is the set of
-// methods for the type. A stub method may be needed when a type
-// inherits a method from an anonymous field. When we need the
-// address of the method, as in a type descriptor, we need to build a
-// little stub which does the required field dereferences and jumps to
-// the real method. LOCATION is the location of the type definition.
-
-void
-Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods,
- Location location)
-{
- if (methods == NULL)
- return;
- for (Methods::const_iterator p = methods->begin();
- p != methods->end();
- ++p)
- {
- Method* m = p->second;
- if (m->is_ambiguous() || !m->needs_stub_method())
- continue;
-
- const std::string& name(p->first);
-
- // Build a stub method.
-
- const Function_type* fntype = m->type();
-
- static unsigned int counter;
- char buf[100];
- snprintf(buf, sizeof buf, "$this%u", counter);
- ++counter;
-
- Type* receiver_type = const_cast<Type*>(type);
- if (!m->is_value_method())
- receiver_type = Type::make_pointer_type(receiver_type);
- Location receiver_location = m->receiver_location();
- Typed_identifier* receiver = new Typed_identifier(buf, receiver_type,
- receiver_location);
-
- const Typed_identifier_list* fnparams = fntype->parameters();
- Typed_identifier_list* stub_params;
- if (fnparams == NULL || fnparams->empty())
- stub_params = NULL;
- else
- {
- // We give each stub parameter a unique name.
- stub_params = new Typed_identifier_list();
- for (Typed_identifier_list::const_iterator pp = fnparams->begin();
- pp != fnparams->end();
- ++pp)
- {
- char pbuf[100];
- snprintf(pbuf, sizeof pbuf, "$p%u", counter);
- stub_params->push_back(Typed_identifier(pbuf, pp->type(),
- pp->location()));
- ++counter;
- }
- }
-
- const Typed_identifier_list* fnresults = fntype->results();
- Typed_identifier_list* stub_results;
- if (fnresults == NULL || fnresults->empty())
- stub_results = NULL;
- else
- {
- // We create the result parameters without any names, since
- // we won't refer to them.
- stub_results = new Typed_identifier_list();
- for (Typed_identifier_list::const_iterator pr = fnresults->begin();
- pr != fnresults->end();
- ++pr)
- stub_results->push_back(Typed_identifier("", pr->type(),
- pr->location()));
- }
-
- Function_type* stub_type = Type::make_function_type(receiver,
- stub_params,
- stub_results,
- fntype->location());
- if (fntype->is_varargs())
- stub_type->set_is_varargs();
-
- // We only create the function in the package which creates the
- // type.
- const Package* package;
- if (type->named_type() == NULL)
- package = NULL;
- else
- package = type->named_type()->named_object()->package();
- Named_object* stub;
- if (package != NULL)
- stub = Named_object::make_function_declaration(name, package,
- stub_type, location);
- else
- {
- stub = gogo->start_function(name, stub_type, false,
- fntype->location());
- Type::build_one_stub_method(gogo, m, buf, stub_params,
- fntype->is_varargs(), location);
- gogo->finish_function(fntype->location());
-
- if (m->nointerface() && stub->is_function())
- stub->func_value()->set_nointerface();
- }
-
- m->set_stub_object(stub);
- }
-}
-
-// Build a stub method which adjusts the receiver as required to call
-// METHOD. RECEIVER_NAME is the name we used for the receiver.
-// PARAMS is the list of function parameters.
-
-void
-Type::build_one_stub_method(Gogo* gogo, Method* method,
- const char* receiver_name,
- const Typed_identifier_list* params,
- bool is_varargs,
- Location location)
-{
- Named_object* receiver_object = gogo->lookup(receiver_name, NULL);
- go_assert(receiver_object != NULL);
-
- Expression* expr = Expression::make_var_reference(receiver_object, location);
- expr = Type::apply_field_indexes(expr, method->field_indexes(), location);
- if (expr->type()->points_to() == NULL)
- expr = Expression::make_unary(OPERATOR_AND, expr, location);
-
- Expression_list* arguments;
- if (params == NULL || params->empty())
- arguments = NULL;
- else
- {
- arguments = new Expression_list();
- for (Typed_identifier_list::const_iterator p = params->begin();
- p != params->end();
- ++p)
- {
- Named_object* param = gogo->lookup(p->name(), NULL);
- go_assert(param != NULL);
- Expression* param_ref = Expression::make_var_reference(param,
- location);
- arguments->push_back(param_ref);
- }
- }
-
- Expression* func = method->bind_method(expr, location);
- go_assert(func != NULL);
- Call_expression* call = Expression::make_call(func, arguments, is_varargs,
- location);
- call->set_hidden_fields_are_ok();
- size_t count = call->result_count();
- if (count == 0)
- gogo->add_statement(Statement::make_statement(call, true));
- else
- {
- Expression_list* retvals = new Expression_list();
- if (count <= 1)
- retvals->push_back(call);
- else
- {
- for (size_t i = 0; i < count; ++i)
- retvals->push_back(Expression::make_call_result(call, i));
- }
- Return_statement* retstat = Statement::make_return_statement(retvals,
- location);
-
- // We can return values with hidden fields from a stub. This is
- // necessary if the method is itself hidden.
- retstat->set_hidden_fields_are_ok();
-
- gogo->add_statement(retstat);
- }
-}
-
-// Apply FIELD_INDEXES to EXPR. The field indexes have to be applied
-// in reverse order.
-
-Expression*
-Type::apply_field_indexes(Expression* expr,
- const Method::Field_indexes* field_indexes,
- Location location)
-{
- if (field_indexes == NULL)
- return expr;
- expr = Type::apply_field_indexes(expr, field_indexes->next, location);
- Struct_type* stype = expr->type()->deref()->struct_type();
- go_assert(stype != NULL
- && field_indexes->field_index < stype->field_count());
- if (expr->type()->struct_type() == NULL)
- {
- go_assert(expr->type()->points_to() != NULL);
- expr = Expression::make_unary(OPERATOR_MULT, expr, location);
- go_assert(expr->type()->struct_type() == stype);
- }
- return Expression::make_field_reference(expr, field_indexes->field_index,
- location);
-}
-
-// Return whether NO is a method for which the receiver is a pointer.
-
-bool
-Type::method_expects_pointer(const Named_object* no)
-{
- const Function_type *fntype;
- if (no->is_function())
- fntype = no->func_value()->type();
- else if (no->is_function_declaration())
- fntype = no->func_declaration_value()->type();
- else
- go_unreachable();
- return fntype->receiver()->type()->points_to() != NULL;
-}
-
-// Given a set of methods for a type, METHODS, return the method NAME,
-// or NULL if there isn't one or if it is ambiguous. If IS_AMBIGUOUS
-// is not NULL, then set *IS_AMBIGUOUS to true if the method exists
-// but is ambiguous (and return NULL).
-
-Method*
-Type::method_function(const Methods* methods, const std::string& name,
- bool* is_ambiguous)
-{
- if (is_ambiguous != NULL)
- *is_ambiguous = false;
- if (methods == NULL)
- return NULL;
- Methods::const_iterator p = methods->find(name);
- if (p == methods->end())
- return NULL;
- Method* m = p->second;
- if (m->is_ambiguous())
- {
- if (is_ambiguous != NULL)
- *is_ambiguous = true;
- return NULL;
- }
- return m;
-}
-
-// Return a pointer to the interface method table for TYPE for the
-// interface INTERFACE.
-
-tree
-Type::interface_method_table(Gogo* gogo, Type* type,
- const Interface_type *interface,
- bool is_pointer,
- Interface_method_tables** method_tables,
- Interface_method_tables** pointer_tables)
-{
- go_assert(!interface->is_empty());
-
- Interface_method_tables** pimt = is_pointer ? method_tables : pointer_tables;
-
- if (*pimt == NULL)
- *pimt = new Interface_method_tables(5);
-
- std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
- std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
-
- if (ins.second)
- {
- // This is a new entry in the hash table.
- go_assert(ins.first->second == NULL_TREE);
- ins.first->second = gogo->interface_method_table_for_type(interface,
- type,
- is_pointer);
- }
-
- tree decl = ins.first->second;
- if (decl == error_mark_node)
- return error_mark_node;
- go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL);
- return build_fold_addr_expr(decl);
-}
-
-// Look for field or method NAME for TYPE. Return an Expression for
-// the field or method bound to EXPR. If there is no such field or
-// method, give an appropriate error and return an error expression.
-
-Expression*
-Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
- const std::string& name,
- Location location)
-{
- if (type->deref()->is_error_type())
- return Expression::make_error(location);
-
- const Named_type* nt = type->deref()->named_type();
- const Struct_type* st = type->deref()->struct_type();
- const Interface_type* it = type->interface_type();
-
- // If this is a pointer to a pointer, then it is possible that the
- // pointed-to type has methods.
- bool dereferenced = false;
- if (nt == NULL
- && st == NULL
- && it == NULL
- && type->points_to() != NULL
- && type->points_to()->points_to() != NULL)
- {
- expr = Expression::make_unary(OPERATOR_MULT, expr, location);
- type = type->points_to();
- if (type->deref()->is_error_type())
- return Expression::make_error(location);
- nt = type->points_to()->named_type();
- st = type->points_to()->struct_type();
- dereferenced = true;
- }
-
- bool receiver_can_be_pointer = (expr->type()->points_to() != NULL
- || expr->is_addressable());
- std::vector<const Named_type*> seen;
- bool is_method = false;
- bool found_pointer_method = false;
- std::string ambig1;
- std::string ambig2;
- if (Type::find_field_or_method(type, name, receiver_can_be_pointer,
- &seen, NULL, &is_method,
- &found_pointer_method, &ambig1, &ambig2))
- {
- Expression* ret;
- if (!is_method)
- {
- go_assert(st != NULL);
- if (type->struct_type() == NULL)
- {
- go_assert(type->points_to() != NULL);
- expr = Expression::make_unary(OPERATOR_MULT, expr,
- location);
- go_assert(expr->type()->struct_type() == st);
- }
- ret = st->field_reference(expr, name, location);
- }
- else if (it != NULL && it->find_method(name) != NULL)
- ret = Expression::make_interface_field_reference(expr, name,
- location);
- else
- {
- Method* m;
- if (nt != NULL)
- m = nt->method_function(name, NULL);
- else if (st != NULL)
- m = st->method_function(name, NULL);
- else
- go_unreachable();
- go_assert(m != NULL);
- if (dereferenced && m->is_value_method())
- {
- error_at(location,
- "calling value method requires explicit dereference");
- return Expression::make_error(location);
- }
- if (!m->is_value_method() && expr->type()->points_to() == NULL)
- expr = Expression::make_unary(OPERATOR_AND, expr, location);
- ret = m->bind_method(expr, location);
- }
- go_assert(ret != NULL);
- return ret;
- }
- else
- {
- if (!ambig1.empty())
- error_at(location, "%qs is ambiguous via %qs and %qs",
- Gogo::message_name(name).c_str(), ambig1.c_str(),
- ambig2.c_str());
- else if (found_pointer_method)
- error_at(location, "method requires a pointer receiver");
- else if (nt == NULL && st == NULL && it == NULL)
- error_at(location,
- ("reference to field %qs in object which "
- "has no fields or methods"),
- Gogo::message_name(name).c_str());
- else
- {
- bool is_unexported;
- if (!Gogo::is_hidden_name(name))
- is_unexported = false;
- else
- {
- std::string unpacked = Gogo::unpack_hidden_name(name);
- seen.clear();
- is_unexported = Type::is_unexported_field_or_method(gogo, type,
- unpacked,
- &seen);
- }
- if (is_unexported)
- error_at(location, "reference to unexported field or method %qs",
- Gogo::message_name(name).c_str());
- else
- error_at(location, "reference to undefined field or method %qs",
- Gogo::message_name(name).c_str());
- }
- return Expression::make_error(location);
- }
-}
-
-// Look in TYPE for a field or method named NAME, return true if one
-// is found. This looks through embedded anonymous fields and handles
-// ambiguity. If a method is found, sets *IS_METHOD to true;
-// otherwise, if a field is found, set it to false. If
-// RECEIVER_CAN_BE_POINTER is false, then the receiver is a value
-// whose address can not be taken. SEEN is used to avoid infinite
-// recursion on invalid types.
-
-// When returning false, this sets *FOUND_POINTER_METHOD if we found a
-// method we couldn't use because it requires a pointer. LEVEL is
-// used for recursive calls, and can be NULL for a non-recursive call.
-// When this function returns false because it finds that the name is
-// ambiguous, it will store a path to the ambiguous names in *AMBIG1
-// and *AMBIG2. If the name is not found at all, *AMBIG1 and *AMBIG2
-// will be unchanged.
-
-// This function just returns whether or not there is a field or
-// method, and whether it is a field or method. It doesn't build an
-// expression to refer to it. If it is a method, we then look in the
-// list of all methods for the type. If it is a field, the search has
-// to be done again, looking only for fields, and building up the
-// expression as we go.
-
-bool
-Type::find_field_or_method(const Type* type,
- const std::string& name,
- bool receiver_can_be_pointer,
- std::vector<const Named_type*>* seen,
- int* level,
- bool* is_method,
- bool* found_pointer_method,
- std::string* ambig1,
- std::string* ambig2)
-{
- // Named types can have locally defined methods.
- const Named_type* nt = type->named_type();
- if (nt == NULL && type->points_to() != NULL)
- nt = type->points_to()->named_type();
- if (nt != NULL)
- {
- Named_object* no = nt->find_local_method(name);
- if (no != NULL)
- {
- if (receiver_can_be_pointer || !Type::method_expects_pointer(no))
- {
- *is_method = true;
- return true;
- }
-
- // Record that we have found a pointer method in order to
- // give a better error message if we don't find anything
- // else.
- *found_pointer_method = true;
- }
-
- for (std::vector<const Named_type*>::const_iterator p = seen->begin();
- p != seen->end();
- ++p)
- {
- if (*p == nt)
- {
- // We've already seen this type when searching for methods.
- return false;
- }
- }
- }
-
- // Interface types can have methods.
- const Interface_type* it = type->interface_type();
- if (it != NULL && it->find_method(name) != NULL)
- {
- *is_method = true;
- return true;
- }
-
- // Struct types can have fields. They can also inherit fields and
- // methods from anonymous fields.
- const Struct_type* st = type->deref()->struct_type();
- if (st == NULL)
- return false;
- const Struct_field_list* fields = st->fields();
- if (fields == NULL)
- return false;
-
- if (nt != NULL)
- seen->push_back(nt);
-
- int found_level = 0;
- bool found_is_method = false;
- std::string found_ambig1;
- std::string found_ambig2;
- const Struct_field* found_parent = NULL;
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf)
- {
- if (pf->is_field_name(name))
- {
- *is_method = false;
- if (nt != NULL)
- seen->pop_back();
- return true;
- }
-
- if (!pf->is_anonymous())
- continue;
-
- if (pf->type()->deref()->is_error_type()
- || pf->type()->deref()->is_undefined())
- continue;
-
- Named_type* fnt = pf->type()->named_type();
- if (fnt == NULL)
- fnt = pf->type()->deref()->named_type();
- go_assert(fnt != NULL);
-
- int sublevel = level == NULL ? 1 : *level + 1;
- bool sub_is_method;
- std::string subambig1;
- std::string subambig2;
- bool subfound = Type::find_field_or_method(fnt,
- name,
- receiver_can_be_pointer,
- seen,
- &sublevel,
- &sub_is_method,
- found_pointer_method,
- &subambig1,
- &subambig2);
- if (!subfound)
- {
- if (!subambig1.empty())
- {
- // The name was found via this field, but is ambiguous.
- // if the ambiguity is lower or at the same level as
- // anything else we have already found, then we want to
- // pass the ambiguity back to the caller.
- if (found_level == 0 || sublevel <= found_level)
- {
- found_ambig1 = (Gogo::message_name(pf->field_name())
- + '.' + subambig1);
- found_ambig2 = (Gogo::message_name(pf->field_name())
- + '.' + subambig2);
- found_level = sublevel;
- }
- }
- }
- else
- {
- // The name was found via this field. Use the level to see
- // if we want to use this one, or whether it introduces an
- // ambiguity.
- if (found_level == 0 || sublevel < found_level)
- {
- found_level = sublevel;
- found_is_method = sub_is_method;
- found_ambig1.clear();
- found_ambig2.clear();
- found_parent = &*pf;
- }
- else if (sublevel > found_level)
- ;
- else if (found_ambig1.empty())
- {
- // We found an ambiguity.
- go_assert(found_parent != NULL);
- found_ambig1 = Gogo::message_name(found_parent->field_name());
- found_ambig2 = Gogo::message_name(pf->field_name());
- }
- else
- {
- // We found an ambiguity, but we already know of one.
- // Just report the earlier one.
- }
- }
- }
-
- // Here if we didn't find anything FOUND_LEVEL is 0. If we found
- // something ambiguous, FOUND_LEVEL is not 0 and FOUND_AMBIG1 and
- // FOUND_AMBIG2 are not empty. If we found the field, FOUND_LEVEL
- // is not 0 and FOUND_AMBIG1 and FOUND_AMBIG2 are empty.
-
- if (nt != NULL)
- seen->pop_back();
-
- if (found_level == 0)
- return false;
- else if (!found_ambig1.empty())
- {
- go_assert(!found_ambig1.empty());
- ambig1->assign(found_ambig1);
- ambig2->assign(found_ambig2);
- if (level != NULL)
- *level = found_level;
- return false;
- }
- else
- {
- if (level != NULL)
- *level = found_level;
- *is_method = found_is_method;
- return true;
- }
-}
-
-// Return whether NAME is an unexported field or method for TYPE.
-
-bool
-Type::is_unexported_field_or_method(Gogo* gogo, const Type* type,
- const std::string& name,
- std::vector<const Named_type*>* seen)
-{
- const Named_type* nt = type->named_type();
- if (nt == NULL)
- nt = type->deref()->named_type();
- if (nt != NULL)
- {
- if (nt->is_unexported_local_method(gogo, name))
- return true;
-
- for (std::vector<const Named_type*>::const_iterator p = seen->begin();
- p != seen->end();
- ++p)
- {
- if (*p == nt)
- {
- // We've already seen this type.
- return false;
- }
- }
- }
-
- const Interface_type* it = type->interface_type();
- if (it != NULL && it->is_unexported_method(gogo, name))
- return true;
-
- type = type->deref();
-
- const Struct_type* st = type->struct_type();
- if (st != NULL && st->is_unexported_local_field(gogo, name))
- return true;
-
- if (st == NULL)
- return false;
-
- const Struct_field_list* fields = st->fields();
- if (fields == NULL)
- return false;
-
- if (nt != NULL)
- seen->push_back(nt);
-
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf)
- {
- if (pf->is_anonymous()
- && !pf->type()->deref()->is_error_type()
- && !pf->type()->deref()->is_undefined())
- {
- Named_type* subtype = pf->type()->named_type();
- if (subtype == NULL)
- subtype = pf->type()->deref()->named_type();
- if (subtype == NULL)
- {
- // This is an error, but it will be diagnosed elsewhere.
- continue;
- }
- if (Type::is_unexported_field_or_method(gogo, subtype, name, seen))
- {
- if (nt != NULL)
- seen->pop_back();
- return true;
- }
- }
- }
-
- if (nt != NULL)
- seen->pop_back();
-
- return false;
-}
-
-// Class Forward_declaration.
-
-Forward_declaration_type::Forward_declaration_type(Named_object* named_object)
- : Type(TYPE_FORWARD),
- named_object_(named_object->resolve()), warned_(false)
-{
- go_assert(this->named_object_->is_unknown()
- || this->named_object_->is_type_declaration());
-}
-
-// Return the named object.
-
-Named_object*
-Forward_declaration_type::named_object()
-{
- return this->named_object_->resolve();
-}
-
-const Named_object*
-Forward_declaration_type::named_object() const
-{
- return this->named_object_->resolve();
-}
-
-// Return the name of the forward declared type.
-
-const std::string&
-Forward_declaration_type::name() const
-{
- return this->named_object()->name();
-}
-
-// Warn about a use of a type which has been declared but not defined.
-
-void
-Forward_declaration_type::warn() const
-{
- Named_object* no = this->named_object_->resolve();
- if (no->is_unknown())
- {
- // The name was not defined anywhere.
- if (!this->warned_)
- {
- error_at(this->named_object_->location(),
- "use of undefined type %qs",
- no->message_name().c_str());
- this->warned_ = true;
- }
- }
- else if (no->is_type_declaration())
- {
- // The name was seen as a type, but the type was never defined.
- if (no->type_declaration_value()->using_type())
- {
- error_at(this->named_object_->location(),
- "use of undefined type %qs",
- no->message_name().c_str());
- this->warned_ = true;
- }
- }
- else
- {
- // The name was defined, but not as a type.
- if (!this->warned_)
- {
- error_at(this->named_object_->location(), "expected type");
- this->warned_ = true;
- }
- }
-}
-
-// Get the base type of a declaration. This gives an error if the
-// type has not yet been defined.
-
-Type*
-Forward_declaration_type::real_type()
-{
- if (this->is_defined())
- return this->named_object()->type_value();
- else
- {
- this->warn();
- return Type::make_error_type();
- }
-}
-
-const Type*
-Forward_declaration_type::real_type() const
-{
- if (this->is_defined())
- return this->named_object()->type_value();
- else
- {
- this->warn();
- return Type::make_error_type();
- }
-}
-
-// Return whether the base type is defined.
-
-bool
-Forward_declaration_type::is_defined() const
-{
- return this->named_object()->is_type();
-}
-
-// Add a method. This is used when methods are defined before the
-// type.
-
-Named_object*
-Forward_declaration_type::add_method(const std::string& name,
- Function* function)
-{
- Named_object* no = this->named_object();
- if (no->is_unknown())
- no->declare_as_type();
- return no->type_declaration_value()->add_method(name, function);
-}
-
-// Add a method declaration. This is used when methods are declared
-// before the type.
-
-Named_object*
-Forward_declaration_type::add_method_declaration(const std::string& name,
- Package* package,
- Function_type* type,
- Location location)
-{
- Named_object* no = this->named_object();
- if (no->is_unknown())
- no->declare_as_type();
- Type_declaration* td = no->type_declaration_value();
- return td->add_method_declaration(name, package, type, location);
-}
-
-// Traversal.
-
-int
-Forward_declaration_type::do_traverse(Traverse* traverse)
-{
- if (this->is_defined()
- && Type::traverse(this->real_type(), traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- return TRAVERSE_CONTINUE;
-}
-
-// Verify the type.
-
-bool
-Forward_declaration_type::do_verify()
-{
- if (!this->is_defined() && !this->is_nil_constant_as_type())
- {
- this->warn();
- return false;
- }
- return true;
-}
-
-// Get the backend representation for the type.
-
-Btype*
-Forward_declaration_type::do_get_backend(Gogo* gogo)
-{
- if (this->is_defined())
- return Type::get_named_base_btype(gogo, this->real_type());
-
- if (this->warned_)
- return gogo->backend()->error_type();
-
- // We represent an undefined type as a struct with no fields. That
- // should work fine for the backend, since the same case can arise
- // in C.
- std::vector<Backend::Btyped_identifier> fields;
- Btype* bt = gogo->backend()->struct_type(fields);
- return gogo->backend()->named_type(this->name(), bt,
- this->named_object()->location());
-}
-
-// Build a type descriptor for a forwarded type.
-
-Expression*
-Forward_declaration_type::do_type_descriptor(Gogo* gogo, Named_type* name)
-{
- Location ploc = Linemap::predeclared_location();
- if (!this->is_defined())
- return Expression::make_error(ploc);
- else
- {
- Type* t = this->real_type();
- if (name != NULL)
- return this->named_type_descriptor(gogo, t, name);
- else
- return Expression::make_type_descriptor(t, ploc);
- }
-}
-
-// The reflection string.
-
-void
-Forward_declaration_type::do_reflection(Gogo* gogo, std::string* ret) const
-{
- this->append_reflection(this->real_type(), gogo, ret);
-}
-
-// The mangled name.
-
-void
-Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- if (this->is_defined())
- this->append_mangled_name(this->real_type(), gogo, ret);
- else
- {
- const Named_object* no = this->named_object();
- std::string name;
- if (no->package() == NULL)
- name = gogo->pkgpath_symbol();
- else
- name = no->package()->pkgpath_symbol();
- name += '.';
- name += Gogo::unpack_hidden_name(no->name());
- char buf[20];
- snprintf(buf, sizeof buf, "N%u_",
- static_cast<unsigned int>(name.length()));
- ret->append(buf);
- ret->append(name);
- }
-}
-
-// Export a forward declaration. This can happen when a defined type
-// refers to a type which is only declared (and is presumably defined
-// in some other file in the same package).
-
-void
-Forward_declaration_type::do_export(Export*) const
-{
- // If there is a base type, that should be exported instead of this.
- go_assert(!this->is_defined());
-
- // We don't output anything.
-}
-
-// Make a forward declaration.
-
-Type*
-Type::make_forward_declaration(Named_object* named_object)
-{
- return new Forward_declaration_type(named_object);
-}
-
-// Class Typed_identifier_list.
-
-// Sort the entries by name.
-
-struct Typed_identifier_list_sort
-{
- public:
- bool
- operator()(const Typed_identifier& t1, const Typed_identifier& t2) const
- { return t1.name() < t2.name(); }
-};
-
-void
-Typed_identifier_list::sort_by_name()
-{
- std::sort(this->entries_.begin(), this->entries_.end(),
- Typed_identifier_list_sort());
-}
-
-// Traverse types.
-
-int
-Typed_identifier_list::traverse(Traverse* traverse)
-{
- for (Typed_identifier_list::const_iterator p = this->begin();
- p != this->end();
- ++p)
- {
- if (Type::traverse(p->type(), traverse) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
-// Copy the list.
-
-Typed_identifier_list*
-Typed_identifier_list::copy() const
-{
- Typed_identifier_list* ret = new Typed_identifier_list();
- for (Typed_identifier_list::const_iterator p = this->begin();
- p != this->end();
- ++p)
- ret->push_back(Typed_identifier(p->name(), p->type(), p->location()));
- return ret;
-}
diff --git a/gcc-4.8.1/gcc/go/gofrontend/types.h b/gcc-4.8.1/gcc/go/gofrontend/types.h
deleted file mode 100644
index 3922a634f..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/types.h
+++ /dev/null
@@ -1,3085 +0,0 @@
-// types.h -- Go frontend types. -*- C++ -*-
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef GO_TYPES_H
-#define GO_TYPES_H
-
-#include "go-linemap.h"
-
-class Gogo;
-class Package;
-class Traverse;
-class Typed_identifier;
-class Typed_identifier_list;
-class Integer_type;
-class Float_type;
-class Complex_type;
-class String_type;
-class Function_type;
-class Struct_field;
-class Struct_field_list;
-class Struct_type;
-class Pointer_type;
-class Array_type;
-class Map_type;
-class Channel_type;
-class Interface_type;
-class Named_type;
-class Forward_declaration_type;
-class Method;
-class Methods;
-class Type_hash_identical;
-class Type_identical;
-class Expression;
-class Expression_list;
-class Call_expression;
-class Field_reference_expression;
-class Bound_method_expression;
-class Bindings;
-class Named_object;
-class Function;
-class Translate_context;
-class Export;
-class Import;
-class Btype;
-class Bexpression;
-class Bvariable;
-
-// Type codes used in type descriptors. These must match the values
-// in libgo/runtime/go-type.h. They also match the values in the gc
-// compiler in src/cmd/gc/reflect.c and src/pkg/runtime/type.go,
-// although this is not required.
-
-static const int RUNTIME_TYPE_KIND_BOOL = 1;
-static const int RUNTIME_TYPE_KIND_INT = 2;
-static const int RUNTIME_TYPE_KIND_INT8 = 3;
-static const int RUNTIME_TYPE_KIND_INT16 = 4;
-static const int RUNTIME_TYPE_KIND_INT32 = 5;
-static const int RUNTIME_TYPE_KIND_INT64 = 6;
-static const int RUNTIME_TYPE_KIND_UINT = 7;
-static const int RUNTIME_TYPE_KIND_UINT8 = 8;
-static const int RUNTIME_TYPE_KIND_UINT16 = 9;
-static const int RUNTIME_TYPE_KIND_UINT32 = 10;
-static const int RUNTIME_TYPE_KIND_UINT64 = 11;
-static const int RUNTIME_TYPE_KIND_UINTPTR = 12;
-static const int RUNTIME_TYPE_KIND_FLOAT32 = 13;
-static const int RUNTIME_TYPE_KIND_FLOAT64 = 14;
-static const int RUNTIME_TYPE_KIND_COMPLEX64 = 15;
-static const int RUNTIME_TYPE_KIND_COMPLEX128 = 16;
-static const int RUNTIME_TYPE_KIND_ARRAY = 17;
-static const int RUNTIME_TYPE_KIND_CHAN = 18;
-static const int RUNTIME_TYPE_KIND_FUNC = 19;
-static const int RUNTIME_TYPE_KIND_INTERFACE = 20;
-static const int RUNTIME_TYPE_KIND_MAP = 21;
-static const int RUNTIME_TYPE_KIND_PTR = 22;
-static const int RUNTIME_TYPE_KIND_SLICE = 23;
-static const int RUNTIME_TYPE_KIND_STRING = 24;
-static const int RUNTIME_TYPE_KIND_STRUCT = 25;
-static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26;
-
-static const int RUNTIME_TYPE_KIND_NO_POINTERS = (1 << 7);
-
-// To build the complete list of methods for a named type we need to
-// gather all methods from anonymous fields. Those methods may
-// require an arbitrary set of indirections and field offsets. There
-// is also the possibility of ambiguous methods, which we could ignore
-// except that we want to give a better error message for that case.
-// This is a base class. There are two types of methods: named
-// methods, and methods which are inherited from an anonymous field of
-// interface type.
-
-class Method
-{
- public:
- // For methods in anonymous types we need to know the sequence of
- // field references used to extract the pointer to pass to the
- // method. Since each method for a particular anonymous field will
- // have the sequence of field indexes, and since the indexes can be
- // shared going down the chain, we use a manually managed linked
- // list. The first entry in the list is the field index for the
- // last field, the one passed to the method.
-
- struct Field_indexes
- {
- const Field_indexes* next;
- unsigned int field_index;
- };
-
- virtual ~Method()
- { }
-
- // Get the list of field indexes.
- const Field_indexes*
- field_indexes() const
- { return this->field_indexes_; }
-
- // Get the depth.
- unsigned int
- depth() const
- { return this->depth_; }
-
- // Return whether this is a value method--a method which does not
- // require a pointer expression.
- bool
- is_value_method() const
- { return this->is_value_method_; }
-
- // Return whether we need a stub method--this is true if we can't
- // just pass the main object to the method.
- bool
- needs_stub_method() const
- { return this->needs_stub_method_; }
-
- // Return whether this is an ambiguous method name.
- bool
- is_ambiguous() const
- { return this->is_ambiguous_; }
-
- // Note that this method is ambiguous.
- void
- set_is_ambiguous()
- { this->is_ambiguous_ = true; }
-
- // Return the type of the method.
- Function_type*
- type() const
- { return this->do_type(); }
-
- // Return the location of the method receiver.
- Location
- receiver_location() const
- { return this->do_receiver_location(); }
-
- // Return an expression which binds this method to EXPR. This is
- // something which can be used with a function call.
- Expression*
- bind_method(Expression* expr, Location location) const;
-
- // Return the named object for this method. This may only be called
- // after methods are finalized.
- Named_object*
- named_object() const;
-
- // Get the stub object.
- Named_object*
- stub_object() const
- {
- go_assert(this->stub_ != NULL);
- return this->stub_;
- }
-
- // Set the stub object.
- void
- set_stub_object(Named_object* no)
- {
- go_assert(this->stub_ == NULL);
- this->stub_ = no;
- }
-
- // Return true if this method should not participate in any
- // interfaces.
- bool
- nointerface() const
- { return this->do_nointerface(); }
-
- protected:
- // These objects are only built by the child classes.
- Method(const Field_indexes* field_indexes, unsigned int depth,
- bool is_value_method, bool needs_stub_method)
- : field_indexes_(field_indexes), depth_(depth), stub_(NULL),
- is_value_method_(is_value_method), needs_stub_method_(needs_stub_method),
- is_ambiguous_(false)
- { }
-
- // The named object for this method.
- virtual Named_object*
- do_named_object() const = 0;
-
- // The type of the method.
- virtual Function_type*
- do_type() const = 0;
-
- // Return the location of the method receiver.
- virtual Location
- do_receiver_location() const = 0;
-
- // Bind a method to an object.
- virtual Expression*
- do_bind_method(Expression* expr, Location location) const = 0;
-
- // Return whether this method should not participate in interfaces.
- virtual bool
- do_nointerface() const = 0;
-
- private:
- // The sequence of field indexes used for this method. If this is
- // NULL, then the method is defined for the current type.
- const Field_indexes* field_indexes_;
- // The depth at which this method was found.
- unsigned int depth_;
- // If a stub method is required, this is its object. This is only
- // set after stub methods are built in finalize_methods.
- Named_object* stub_;
- // Whether this is a value method--a method that does not require a
- // pointer.
- bool is_value_method_;
- // Whether a stub method is required.
- bool needs_stub_method_;
- // Whether this method is ambiguous.
- bool is_ambiguous_;
-};
-
-// A named method. This is what you get with a method declaration,
-// either directly on the type, or inherited from some anonymous
-// embedded field.
-
-class Named_method : public Method
-{
- public:
- Named_method(Named_object* named_object, const Field_indexes* field_indexes,
- unsigned int depth, bool is_value_method,
- bool needs_stub_method)
- : Method(field_indexes, depth, is_value_method, needs_stub_method),
- named_object_(named_object)
- { }
-
- protected:
- // Get the Named_object for the method.
- Named_object*
- do_named_object() const
- { return this->named_object_; }
-
- // The type of the method.
- Function_type*
- do_type() const;
-
- // Return the location of the method receiver.
- Location
- do_receiver_location() const;
-
- // Bind a method to an object.
- Expression*
- do_bind_method(Expression* expr, Location location) const;
-
- // Return whether this method should not participate in interfaces.
- bool
- do_nointerface() const;
-
- private:
- // The method itself. For a method which needs a stub, this starts
- // out as the underlying method, and is later replaced with the stub
- // method.
- Named_object* named_object_;
-};
-
-// An interface method. This is used when an interface appears as an
-// anonymous field in a named struct.
-
-class Interface_method : public Method
-{
- public:
- Interface_method(const std::string& name, Location location,
- Function_type* fntype, const Field_indexes* field_indexes,
- unsigned int depth)
- : Method(field_indexes, depth, true, true),
- name_(name), location_(location), fntype_(fntype)
- { }
-
- protected:
- // Get the Named_object for the method. This should never be
- // called, as we always create a stub.
- Named_object*
- do_named_object() const
- { go_unreachable(); }
-
- // The type of the method.
- Function_type*
- do_type() const
- { return this->fntype_; }
-
- // Return the location of the method receiver.
- Location
- do_receiver_location() const
- { return this->location_; }
-
- // Bind a method to an object.
- Expression*
- do_bind_method(Expression* expr, Location location) const;
-
- // Return whether this method should not participate in interfaces.
- bool
- do_nointerface() const
- { return false; }
-
- private:
- // The name of the interface method to call.
- std::string name_;
- // The location of the definition of the interface method.
- Location location_;
- // The type of the interface method.
- Function_type* fntype_;
-};
-
-// A mapping from method name to Method. This is a wrapper around a
-// hash table.
-
-class Methods
-{
- private:
- typedef Unordered_map(std::string, Method*) Method_map;
-
- public:
- typedef Method_map::const_iterator const_iterator;
-
- Methods()
- : methods_()
- { }
-
- // Insert a new method. Returns true if it was inserted, false if
- // it was overidden or ambiguous.
- bool
- insert(const std::string& name, Method* m);
-
- // The number of (unambiguous) methods.
- size_t
- count() const;
-
- // Iterate.
- const_iterator
- begin() const
- { return this->methods_.begin(); }
-
- const_iterator
- end() const
- { return this->methods_.end(); }
-
- // Lookup.
- const_iterator
- find(const std::string& name) const
- { return this->methods_.find(name); }
-
- private:
- Method_map methods_;
-};
-
-// The base class for all types.
-
-class Type
-{
- public:
- // The types of types.
- enum Type_classification
- {
- TYPE_ERROR,
- TYPE_VOID,
- TYPE_BOOLEAN,
- TYPE_INTEGER,
- TYPE_FLOAT,
- TYPE_COMPLEX,
- TYPE_STRING,
- TYPE_SINK,
- TYPE_FUNCTION,
- TYPE_POINTER,
- TYPE_NIL,
- TYPE_CALL_MULTIPLE_RESULT,
- TYPE_STRUCT,
- TYPE_ARRAY,
- TYPE_MAP,
- TYPE_CHANNEL,
- TYPE_INTERFACE,
- TYPE_NAMED,
- TYPE_FORWARD
- };
-
- virtual ~Type();
-
- // Creators.
-
- static Type*
- make_error_type();
-
- static Type*
- make_void_type();
-
- // Get the unnamed bool type.
- static Type*
- make_boolean_type();
-
- // Get the named type "bool".
- static Named_type*
- lookup_bool_type();
-
- // Make the named type "bool".
- static Named_type*
- make_named_bool_type();
-
- // Make an abstract integer type.
- static Integer_type*
- make_abstract_integer_type();
-
- // Make an abstract type for a character constant.
- static Integer_type*
- make_abstract_character_type();
-
- // Make a named integer type with a specified size.
- // RUNTIME_TYPE_KIND is the code to use in reflection information,
- // to distinguish int and int32.
- static Named_type*
- make_integer_type(const char* name, bool is_unsigned, int bits,
- int runtime_type_kind);
-
- // Look up a named integer type.
- static Named_type*
- lookup_integer_type(const char* name);
-
- // Make an abstract floating point type.
- static Float_type*
- make_abstract_float_type();
-
- // Make a named floating point type with a specific size.
- // RUNTIME_TYPE_KIND is the code to use in reflection information,
- // to distinguish float and float32.
- static Named_type*
- make_float_type(const char* name, int bits, int runtime_type_kind);
-
- // Look up a named float type.
- static Named_type*
- lookup_float_type(const char* name);
-
- // Make an abstract complex type.
- static Complex_type*
- make_abstract_complex_type();
-
- // Make a named complex type with a specific size.
- // RUNTIME_TYPE_KIND is the code to use in reflection information,
- // to distinguish complex and complex64.
- static Named_type*
- make_complex_type(const char* name, int bits, int runtime_type_kind);
-
- // Look up a named complex type.
- static Named_type*
- lookup_complex_type(const char* name);
-
- // Get the unnamed string type.
- static Type*
- make_string_type();
-
- // Get the named type "string".
- static Named_type*
- lookup_string_type();
-
- // Make the named type "string".
- static Named_type*
- make_named_string_type();
-
- static Type*
- make_sink_type();
-
- static Function_type*
- make_function_type(Typed_identifier* receiver,
- Typed_identifier_list* parameters,
- Typed_identifier_list* results,
- Location);
-
- static Pointer_type*
- make_pointer_type(Type*);
-
- static Type*
- make_nil_type();
-
- static Type*
- make_call_multiple_result_type(Call_expression*);
-
- static Struct_type*
- make_struct_type(Struct_field_list* fields, Location);
-
- static Array_type*
- make_array_type(Type* element_type, Expression* length);
-
- static Map_type*
- make_map_type(Type* key_type, Type* value_type, Location);
-
- static Channel_type*
- make_channel_type(bool send, bool receive, Type*);
-
- static Interface_type*
- make_interface_type(Typed_identifier_list* methods, Location);
-
- static Interface_type*
- make_empty_interface_type(Location);
-
- static Type*
- make_type_descriptor_type();
-
- static Type*
- make_type_descriptor_ptr_type();
-
- static Named_type*
- make_named_type(Named_object*, Type*, Location);
-
- static Type*
- make_forward_declaration(Named_object*);
-
- // Traverse a type.
- static int
- traverse(Type*, Traverse*);
-
- // Verify the type. This is called after parsing, and verifies that
- // types are complete and meet the language requirements. This
- // returns false if the type is invalid and we should not continue
- // traversing it.
- bool
- verify()
- { return this->do_verify(); }
-
- // 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, 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
- // is an equivalence relation.
- static bool
- are_compatible_for_binop(const Type* t1, const Type* t2);
-
- // Return true if two types are compatible for use with the
- // comparison operator. IS_EQUALITY_OP is true if this is an
- // equality comparison, false if it is an ordered comparison. This
- // is an equivalence relation. If this returns false, and REASON is
- // not NULL, it sets *REASON.
- static bool
- are_compatible_for_comparison(bool is_equality_op, const Type *t1,
- const Type *t2, std::string* reason);
-
- // Return true if a type is comparable with itself. This is true of
- // most types, but false for, e.g., function types.
- bool
- is_comparable() const
- { return Type::are_compatible_for_comparison(true, this, this, NULL); }
-
- // Return true if a value with type RHS is assignable to a variable
- // with type LHS. This is not an equivalence relation. If this
- // returns false, and REASON is not NULL, it sets *REASON.
- static bool
- are_assignable(const Type* lhs, const Type* rhs, std::string* reason);
-
- // Return true if a value with type RHS is assignable to a variable
- // with type LHS, ignoring any assignment of hidden fields
- // (unexported fields of a type imported from another package).
- // This is like the are_assignable method.
- static bool
- are_assignable_hidden_ok(const Type* lhs, const Type* rhs,
- std::string* reason);
-
- // Return true if a value with type RHS may be converted to type
- // LHS. If this returns false, and REASON is not NULL, it sets
- // *REASON.
- static bool
- are_convertible(const Type* lhs, const Type* rhs, std::string* reason);
-
- // Whether this type has any hidden fields which are not visible in
- // the current compilation, such as a field whose name begins with a
- // lower case letter in a struct imported from a different package.
- // WITHIN is not NULL if we are looking at fields in a named type.
- bool
- has_hidden_fields(const Named_type* within, std::string* reason) const;
-
- // Return true if values of this type can be compared using an
- // identity function which gets nothing but a pointer to the value
- // and a size.
- bool
- compare_is_identity(Gogo* gogo)
- { return this->do_compare_is_identity(gogo); }
-
- // Return a hash code for this type for the method hash table.
- // Types which are equivalent according to are_identical will have
- // the same hash code.
- unsigned int
- hash_for_method(Gogo*) const;
-
- // Return the type classification.
- Type_classification
- classification() const
- { return this->classification_; }
-
- // Return the base type for this type. This looks through forward
- // declarations and names. Using this with a forward declaration
- // which has not been defined will return an error type.
- Type*
- base();
-
- const Type*
- base() const;
-
- // Return the type skipping defined forward declarations. If this
- // type is a forward declaration which has not been defined, it will
- // return the Forward_declaration_type. This differs from base() in
- // that it will return a Named_type, and for a
- // Forward_declaration_type which is not defined it will return that
- // type rather than an error type.
- Type*
- forwarded();
-
- const Type*
- forwarded() const;
-
- // Return true if this is a basic type: a type which is not composed
- // of other types, and is not void.
- bool
- is_basic_type() const;
-
- // Return true if this is an abstract type--an integer, floating
- // point, or complex type whose size has not been determined.
- bool
- is_abstract() const;
-
- // Return a non-abstract version of an abstract type.
- Type*
- make_non_abstract_type();
-
- // Return true if this type is or contains a pointer. This
- // determines whether the garbage collector needs to look at a value
- // of this type.
- bool
- has_pointer() const
- { return this->do_has_pointer(); }
-
- // Return true if this is the error type. This returns false for a
- // type which is not defined, as it is called by the parser before
- // all types are defined.
- bool
- is_error_type() const;
-
- // Return true if this is the error type or if the type is
- // undefined. If the type is undefined, this will give an error.
- // This should only be called after parsing is complete.
- bool
- is_error() const
- { return this->base()->is_error_type(); }
-
- // Return true if this is a void type.
- bool
- is_void_type() const
- { return this->classification_ == TYPE_VOID; }
-
- // If this is an integer type, return the Integer_type. Otherwise,
- // return NULL. This is a controlled dynamic_cast.
- Integer_type*
- integer_type()
- { return this->convert<Integer_type, TYPE_INTEGER>(); }
-
- const Integer_type*
- integer_type() const
- { return this->convert<const Integer_type, TYPE_INTEGER>(); }
-
- // If this is a floating point type, return the Float_type.
- // Otherwise, return NULL. This is a controlled dynamic_cast.
- Float_type*
- float_type()
- { return this->convert<Float_type, TYPE_FLOAT>(); }
-
- const Float_type*
- float_type() const
- { return this->convert<const Float_type, TYPE_FLOAT>(); }
-
- // If this is a complex type, return the Complex_type. Otherwise,
- // return NULL.
- Complex_type*
- complex_type()
- { return this->convert<Complex_type, TYPE_COMPLEX>(); }
-
- const Complex_type*
- complex_type() const
- { return this->convert<const Complex_type, TYPE_COMPLEX>(); }
-
- // Return whether this is a numeric type.
- bool
- is_numeric_type() const
- {
- Type_classification tc = this->base()->classification_;
- return tc == TYPE_INTEGER || tc == TYPE_FLOAT || tc == TYPE_COMPLEX;
- }
-
- // Return true if this is a boolean type.
- bool
- is_boolean_type() const
- { return this->base()->classification_ == TYPE_BOOLEAN; }
-
- // Return true if this is an abstract boolean type.
- bool
- is_abstract_boolean_type() const
- { return this->classification_ == TYPE_BOOLEAN; }
-
- // Return true if this is a string type.
- bool
- is_string_type() const
- { return this->base()->classification_ == TYPE_STRING; }
-
- // Return true if this is an abstract string type.
- bool
- is_abstract_string_type() const
- { return this->classification_ == TYPE_STRING; }
-
- // Return true if this is the sink type. This is the type of the
- // blank identifier _.
- bool
- is_sink_type() const
- { return this->base()->classification_ == TYPE_SINK; }
-
- // If this is a function type, return it. Otherwise, return NULL.
- Function_type*
- function_type()
- { return this->convert<Function_type, TYPE_FUNCTION>(); }
-
- const Function_type*
- function_type() const
- { return this->convert<const Function_type, TYPE_FUNCTION>(); }
-
- // If this is a pointer type, return the type to which it points.
- // Otherwise, return NULL.
- Type*
- points_to() const;
-
- // If this is a pointer type, return the type to which it points.
- // Otherwise, return the type itself.
- Type*
- deref()
- {
- Type* pt = this->points_to();
- return pt != NULL ? pt : this;
- }
-
- const Type*
- deref() const
- {
- const Type* pt = this->points_to();
- return pt != NULL ? pt : this;
- }
-
- // Return true if this is the nil type. We don't use base() here,
- // because this can be called during parse, and there is no way to
- // name the nil type anyhow.
- bool
- is_nil_type() const
- { return this->classification_ == TYPE_NIL; }
-
- // Return true if this is the predeclared constant nil being used as
- // a type. This is what the parser produces for type switches which
- // use "case nil".
- bool
- is_nil_constant_as_type() const;
-
- // Return true if this is the return type of a function which
- // returns multiple values.
- bool
- is_call_multiple_result_type() const
- { return this->base()->classification_ == TYPE_CALL_MULTIPLE_RESULT; }
-
- // If this is a struct type, return it. Otherwise, return NULL.
- Struct_type*
- struct_type()
- { return this->convert<Struct_type, TYPE_STRUCT>(); }
-
- const Struct_type*
- struct_type() const
- { return this->convert<const Struct_type, TYPE_STRUCT>(); }
-
- // If this is an array type, return it. Otherwise, return NULL.
- Array_type*
- array_type()
- { return this->convert<Array_type, TYPE_ARRAY>(); }
-
- const Array_type*
- array_type() const
- { return this->convert<const Array_type, TYPE_ARRAY>(); }
-
- // Return whether if this is a slice type.
- bool
- is_slice_type() const;
-
- // If this is a map type, return it. Otherwise, return NULL.
- Map_type*
- map_type()
- { return this->convert<Map_type, TYPE_MAP>(); }
-
- const Map_type*
- map_type() const
- { return this->convert<const Map_type, TYPE_MAP>(); }
-
- // If this is a channel type, return it. Otherwise, return NULL.
- Channel_type*
- channel_type()
- { return this->convert<Channel_type, TYPE_CHANNEL>(); }
-
- const Channel_type*
- channel_type() const
- { return this->convert<const Channel_type, TYPE_CHANNEL>(); }
-
- // If this is an interface type, return it. Otherwise, return NULL.
- Interface_type*
- interface_type()
- { return this->convert<Interface_type, TYPE_INTERFACE>(); }
-
- const Interface_type*
- interface_type() const
- { return this->convert<const Interface_type, TYPE_INTERFACE>(); }
-
- // If this is a named type, return it. Otherwise, return NULL.
- Named_type*
- named_type();
-
- const Named_type*
- named_type() const;
-
- // If this is a forward declaration, return it. Otherwise, return
- // NULL.
- Forward_declaration_type*
- forward_declaration_type()
- { return this->convert_no_base<Forward_declaration_type, TYPE_FORWARD>(); }
-
- const Forward_declaration_type*
- forward_declaration_type() const
- {
- return this->convert_no_base<const Forward_declaration_type,
- TYPE_FORWARD>();
- }
-
- // Return true if this type is not yet defined.
- bool
- is_undefined() const;
-
- // Return true if this is the unsafe.pointer type. We currently
- // represent that as pointer-to-void.
- bool
- is_unsafe_pointer_type() const
- { return this->points_to() != NULL && this->points_to()->is_void_type(); }
-
- // Look for field or method NAME for TYPE. Return an expression for
- // it, bound to EXPR.
- static Expression*
- bind_field_or_method(Gogo*, const Type* type, Expression* expr,
- const std::string& name, Location);
-
- // Return true if NAME is an unexported field or method of TYPE.
- static bool
- is_unexported_field_or_method(Gogo*, const Type*, const std::string&,
- std::vector<const Named_type*>*);
-
- // Convert the builtin named types.
- static void
- convert_builtin_named_types(Gogo*);
-
- // Return the backend representation of this type.
- Btype*
- get_backend(Gogo*);
-
- // Return a placeholder for the backend representation of the type.
- // This will return a type of the correct size, but for which some
- // of the fields may still need to be completed.
- Btype*
- get_backend_placeholder(Gogo*);
-
- // Finish the backend representation of a placeholder.
- void
- finish_backend(Gogo*, Btype*);
-
- // Build a type descriptor entry for this type. Return a pointer to
- // it. The location is the location which causes us to need the
- // entry.
- tree
- type_descriptor_pointer(Gogo* gogo, Location);
-
- // Return the type reflection string for this type.
- std::string
- reflection(Gogo*) const;
-
- // Return a mangled name for the type. This is a name which can be
- // used in assembler code. Identical types should have the same
- // manged name.
- std::string
- mangled_name(Gogo*) const;
-
- // If the size of the type can be determined, set *PSIZE to the size
- // in bytes and return true. Otherwise, return false. This queries
- // the backend.
- bool
- backend_type_size(Gogo*, unsigned int* psize);
-
- // If the alignment of the type can be determined, set *PALIGN to
- // the alignment in bytes and return true. Otherwise, return false.
- bool
- backend_type_align(Gogo*, unsigned int* palign);
-
- // If the alignment of a struct field of this type can be
- // determined, set *PALIGN to the alignment in bytes and return
- // true. Otherwise, return false.
- bool
- backend_type_field_align(Gogo*, unsigned int* palign);
-
- // Whether the backend size is known.
- bool
- is_backend_type_size_known(Gogo*);
-
- // Get the hash and equality functions for a type.
- void
- type_functions(Gogo*, Named_type* name, Function_type* hash_fntype,
- Function_type* equal_fntype, Named_object** hash_fn,
- Named_object** equal_fn);
-
- // Write the hash and equality type functions.
- void
- write_specific_type_functions(Gogo*, Named_type*,
- const std::string& hash_name,
- Function_type* hash_fntype,
- const std::string& equal_name,
- Function_type* equal_fntype);
-
- // Export the type.
- void
- export_type(Export* exp) const
- { this->do_export(exp); }
-
- // Import a type.
- static Type*
- import_type(Import*);
-
- protected:
- Type(Type_classification);
-
- // Functions implemented by the child class.
-
- // Traverse the subtypes.
- virtual int
- do_traverse(Traverse*);
-
- // Verify the type.
- virtual bool
- do_verify()
- { return true; }
-
- virtual bool
- do_has_pointer() const
- { return false; }
-
- virtual bool
- do_compare_is_identity(Gogo*) = 0;
-
- virtual unsigned int
- do_hash_for_method(Gogo*) const;
-
- virtual Btype*
- do_get_backend(Gogo*) = 0;
-
- virtual Expression*
- do_type_descriptor(Gogo*, Named_type* name) = 0;
-
- virtual void
- do_reflection(Gogo*, std::string*) const = 0;
-
- virtual void
- do_mangled_name(Gogo*, std::string*) const = 0;
-
- virtual void
- do_export(Export*) const;
-
- // Return whether a method expects a pointer as the receiver.
- static bool
- method_expects_pointer(const Named_object*);
-
- // Finalize the methods for a type.
- static void
- finalize_methods(Gogo*, const Type*, Location, Methods**);
-
- // Return a method from a set of methods.
- static Method*
- method_function(const Methods*, const std::string& name,
- bool* is_ambiguous);
-
- // A mapping from interfaces to the associated interface method
- // tables for this type. This maps to a decl.
- typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical,
- Type_identical) Interface_method_tables;
-
- // Return a pointer to the interface method table for TYPE for the
- // interface INTERFACE.
- static tree
- interface_method_table(Gogo* gogo, Type* type,
- const Interface_type *interface, bool is_pointer,
- Interface_method_tables** method_tables,
- Interface_method_tables** pointer_tables);
-
- // Return a composite literal for the type descriptor entry for a
- // type.
- static Expression*
- type_descriptor(Gogo*, Type*);
-
- // Return a composite literal for the type descriptor entry for
- // TYPE, using NAME as the name of the type.
- static Expression*
- named_type_descriptor(Gogo*, Type* type, Named_type* name);
-
- // Return a composite literal for a plain type descriptor for this
- // type with the given kind and name.
- Expression*
- plain_type_descriptor(Gogo*, int runtime_type_kind, Named_type* name);
-
- // Build a composite literal for the basic type descriptor.
- Expression*
- type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*,
- const Methods*, bool only_value_methods);
-
- // Make a builtin struct type from a list of fields.
- static Struct_type*
- make_builtin_struct_type(int nfields, ...);
-
- // Make a builtin named type.
- static Named_type*
- make_builtin_named_type(const char* name, Type* type);
-
- // For the benefit of child class reflection string generation.
- void
- append_reflection(const Type* type, Gogo* gogo, std::string* ret) const
- { type->do_reflection(gogo, ret); }
-
- // For the benefit of child class mangling.
- void
- append_mangled_name(const Type* type, Gogo* gogo, std::string* ret) const
- { type->do_mangled_name(gogo, ret); }
-
- // Incorporate a string into a hash code.
- static unsigned int
- hash_string(const std::string&, unsigned int);
-
- // Return the backend representation for the underlying type of a
- // named type.
- static Btype*
- get_named_base_btype(Gogo* gogo, Type* base_type)
- { return base_type->get_btype_without_hash(gogo); }
-
- private:
- // Convert to the desired type classification, or return NULL. This
- // is a controlled dynamic_cast.
- template<typename Type_class, Type_classification type_classification>
- Type_class*
- convert()
- {
- Type* base = this->base();
- return (base->classification_ == type_classification
- ? static_cast<Type_class*>(base)
- : NULL);
- }
-
- template<typename Type_class, Type_classification type_classification>
- const Type_class*
- convert() const
- {
- const Type* base = this->base();
- return (base->classification_ == type_classification
- ? static_cast<Type_class*>(base)
- : NULL);
- }
-
- template<typename Type_class, Type_classification type_classification>
- Type_class*
- convert_no_base()
- {
- return (this->classification_ == type_classification
- ? static_cast<Type_class*>(this)
- : NULL);
- }
-
- template<typename Type_class, Type_classification type_classification>
- const Type_class*
- convert_no_base() const
- {
- return (this->classification_ == type_classification
- ? static_cast<Type_class*>(this)
- : NULL);
- }
-
- // Support for are_assignable and are_assignable_hidden_ok.
- static bool
- are_assignable_check_hidden(const Type* lhs, const Type* rhs,
- bool check_hidden_fields, std::string* reason);
-
- // Map unnamed types to type descriptor decls.
- typedef Unordered_map_hash(const Type*, Bvariable*, Type_hash_identical,
- Type_identical) Type_descriptor_vars;
-
- static Type_descriptor_vars type_descriptor_vars;
-
- // Build the type descriptor variable for this type.
- void
- make_type_descriptor_var(Gogo*);
-
- // Return the name of the type descriptor variable. If NAME is not
- // NULL, it is the name to use.
- std::string
- type_descriptor_var_name(Gogo*, Named_type* name);
-
- // Return true if the type descriptor for this type should be
- // defined in some other package. If NAME is not NULL, it is the
- // name of this type. If this returns true it sets *PACKAGE to the
- // package where the type descriptor is defined.
- bool
- type_descriptor_defined_elsewhere(Named_type* name, const Package** package);
-
- // Build the hash and equality type functions for a type which needs
- // specific functions.
- void
- specific_type_functions(Gogo*, Named_type*, Function_type* hash_fntype,
- Function_type* equal_fntype, Named_object** hash_fn,
- Named_object** equal_fn);
-
- // Build a composite literal for the uncommon type information.
- Expression*
- uncommon_type_constructor(Gogo*, Type* uncommon_type,
- Named_type*, const Methods*,
- bool only_value_methods) const;
-
- // Build a composite literal for the methods.
- Expression*
- methods_constructor(Gogo*, Type* methods_type, const Methods*,
- bool only_value_methods) const;
-
- // Build a composite literal for one method.
- Expression*
- method_constructor(Gogo*, Type* method_type, const std::string& name,
- const Method*, bool only_value_methods) const;
-
- static tree
- build_receive_return_type(tree type);
-
- // A hash table we use to avoid infinite recursion.
- typedef Unordered_set_hash(const Named_type*, Type_hash_identical,
- Type_identical) Types_seen;
-
- // Add all methods for TYPE to the list of methods for THIS.
- static void
- add_methods_for_type(const Type* type, const Method::Field_indexes*,
- unsigned int depth, bool, bool, Types_seen*,
- Methods**);
-
- static void
- add_local_methods_for_type(const Named_type* type,
- const Method::Field_indexes*,
- unsigned int depth, bool, bool, Methods**);
-
- static void
- add_embedded_methods_for_type(const Type* type,
- const Method::Field_indexes*,
- unsigned int depth, bool, bool, Types_seen*,
- Methods**);
-
- static void
- add_interface_methods_for_type(const Type* type,
- const Method::Field_indexes*,
- unsigned int depth, Methods**);
-
- // Build stub methods for a type.
- static void
- build_stub_methods(Gogo*, const Type* type, const Methods* methods,
- Location);
-
- static void
- build_one_stub_method(Gogo*, Method*, const char* receiver_name,
- const Typed_identifier_list*, bool is_varargs,
- Location);
-
- static Expression*
- apply_field_indexes(Expression*, const Method::Field_indexes*,
- Location);
-
- // Look for a field or method named NAME in TYPE.
- static bool
- find_field_or_method(const Type* type, const std::string& name,
- bool receiver_can_be_pointer,
- std::vector<const Named_type*>*, int* level,
- bool* is_method, bool* found_pointer_method,
- std::string* ambig1, std::string* ambig2);
-
- // Get the backend representation for a type without looking in the
- // hash table for identical types.
- Btype*
- get_btype_without_hash(Gogo*);
-
- // A backend type that may be a placeholder.
- struct Type_btype_entry
- {
- Btype *btype;
- bool is_placeholder;
- };
-
- // A mapping from Type to Btype*, used to ensure that the backend
- // representation of identical types is identical. This is only
- // used for unnamed types.
- typedef Unordered_map_hash(const Type*, Type_btype_entry,
- Type_hash_identical, Type_identical) Type_btypes;
-
- static Type_btypes type_btypes;
-
- // A list of builtin named types.
- static std::vector<Named_type*> named_builtin_types;
-
- // A map from types which need specific type functions to the type
- // functions themselves.
- typedef std::pair<Named_object*, Named_object*> Hash_equal_fn;
- typedef Unordered_map_hash(const Type*, Hash_equal_fn, Type_hash_identical,
- Type_identical) Type_functions;
-
- static Type_functions type_functions_table;
-
- // The type classification.
- Type_classification classification_;
- // The backend representation of the type, once it has been
- // determined.
- Btype* btype_;
- // The type descriptor for this type. This starts out as NULL and
- // is filled in as needed.
- Bvariable* type_descriptor_var_;
-};
-
-// Type hash table operations.
-
-class Type_hash_identical
-{
- public:
- unsigned int
- operator()(const Type* type) const
- { return type->hash_for_method(NULL); }
-};
-
-class Type_identical
-{
- public:
- bool
- operator()(const Type* t1, const Type* t2) const
- { return Type::are_identical(t1, t2, false, NULL); }
-};
-
-// An identifier with a type.
-
-class Typed_identifier
-{
- public:
- Typed_identifier(const std::string& name, Type* type,
- Location location)
- : name_(name), type_(type), location_(location)
- { }
-
- // Get the name.
- const std::string&
- name() const
- { return this->name_; }
-
- // Get the type.
- Type*
- type() const
- { return this->type_; }
-
- // Return the location where the name was seen. This is not always
- // meaningful.
- Location
- location() const
- { return this->location_; }
-
- // Set the type--sometimes we see the identifier before the type.
- void
- set_type(Type* type)
- {
- go_assert(this->type_ == NULL || type->is_error_type());
- this->type_ = type;
- }
-
- private:
- // Identifier name.
- std::string name_;
- // Type.
- Type* type_;
- // The location where the name was seen.
- Location location_;
-};
-
-// A list of Typed_identifiers.
-
-class Typed_identifier_list
-{
- public:
- Typed_identifier_list()
- : entries_()
- { }
-
- // Whether the list is empty.
- bool
- empty() const
- { return this->entries_.empty(); }
-
- // Return the number of entries in the list.
- size_t
- size() const
- { return this->entries_.size(); }
-
- // Add an entry to the end of the list.
- void
- push_back(const Typed_identifier& td)
- { this->entries_.push_back(td); }
-
- // Remove an entry from the end of the list.
- void
- pop_back()
- { this->entries_.pop_back(); }
-
- // Set the type of entry I to TYPE.
- void
- set_type(size_t i, Type* type)
- {
- go_assert(i < this->entries_.size());
- this->entries_[i].set_type(type);
- }
-
- // Sort the entries by name.
- void
- sort_by_name();
-
- // Traverse types.
- int
- traverse(Traverse*);
-
- // Return the first and last elements.
- Typed_identifier&
- front()
- { return this->entries_.front(); }
-
- const Typed_identifier&
- front() const
- { return this->entries_.front(); }
-
- Typed_identifier&
- back()
- { return this->entries_.back(); }
-
- const Typed_identifier&
- back() const
- { return this->entries_.back(); }
-
- const Typed_identifier&
- at(size_t i) const
- { return this->entries_.at(i); }
-
- void
- set(size_t i, const Typed_identifier& t)
- { this->entries_.at(i) = t; }
-
- void
- resize(size_t c)
- {
- go_assert(c <= this->entries_.size());
- this->entries_.resize(c, Typed_identifier("", NULL,
- Linemap::unknown_location()));
- }
-
- void
- reserve(size_t c)
- { this->entries_.reserve(c); }
-
- // Iterators.
-
- typedef std::vector<Typed_identifier>::iterator iterator;
- typedef std::vector<Typed_identifier>::const_iterator const_iterator;
-
- iterator
- begin()
- { return this->entries_.begin(); }
-
- const_iterator
- begin() const
- { return this->entries_.begin(); }
-
- iterator
- end()
- { return this->entries_.end(); }
-
- const_iterator
- end() const
- { return this->entries_.end(); }
-
- // Return a copy of this list. This returns an independent copy of
- // the vector, but does not copy the types.
- Typed_identifier_list*
- copy() const;
-
- private:
- std::vector<Typed_identifier> entries_;
-};
-
-// The type of an integer.
-
-class Integer_type : public Type
-{
- public:
- // Create a new integer type.
- static Named_type*
- create_integer_type(const char* name, bool is_unsigned, int bits,
- int runtime_type_kind);
-
- // Look up an existing integer type.
- static Named_type*
- lookup_integer_type(const char* name);
-
- // Create an abstract integer type.
- static Integer_type*
- create_abstract_integer_type();
-
- // Create an abstract character type.
- static Integer_type*
- create_abstract_character_type();
-
- // Whether this is an abstract integer type.
- bool
- is_abstract() const
- { return this->is_abstract_; }
-
- // Whether this is an unsigned type.
- bool
- is_unsigned() const
- { return this->is_unsigned_; }
-
- // The number of bits.
- int
- bits() const
- { return this->bits_; }
-
- // Whether this type is the same as T.
- bool
- is_identical(const Integer_type* t) const;
-
- // Whether this is the type "byte" or another name for "byte".
- bool
- is_byte() const
- { return this->is_byte_; }
-
- // Mark this as the "byte" type.
- void
- set_is_byte()
- { this->is_byte_ = true; }
-
- // Whether this is the type "rune" or another name for "rune".
- bool
- is_rune() const
- { return this->is_rune_; }
-
- // Mark this as the "rune" type.
- void
- set_is_rune()
- { this->is_rune_ = true; }
-
-protected:
- bool
- do_compare_is_identity(Gogo*)
- { return true; }
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string*) const;
-
- private:
- Integer_type(bool is_abstract, bool is_unsigned, int bits,
- int runtime_type_kind)
- : Type(TYPE_INTEGER),
- is_abstract_(is_abstract), is_unsigned_(is_unsigned), is_byte_(false),
- is_rune_(false), bits_(bits), runtime_type_kind_(runtime_type_kind)
- { }
-
- // Map names of integer types to the types themselves.
- typedef std::map<std::string, Named_type*> Named_integer_types;
- static Named_integer_types named_integer_types;
-
- // True if this is an abstract type.
- bool is_abstract_;
- // True if this is an unsigned type.
- bool is_unsigned_;
- // True if this is the byte type.
- bool is_byte_;
- // True if this is the rune type.
- bool is_rune_;
- // The number of bits.
- int bits_;
- // The runtime type code used in the type descriptor for this type.
- int runtime_type_kind_;
-};
-
-// The type of a floating point number.
-
-class Float_type : public Type
-{
- public:
- // Create a new float type.
- static Named_type*
- create_float_type(const char* name, int bits, int runtime_type_kind);
-
- // Look up an existing float type.
- static Named_type*
- lookup_float_type(const char* name);
-
- // Create an abstract float type.
- static Float_type*
- create_abstract_float_type();
-
- // Whether this is an abstract float type.
- bool
- is_abstract() const
- { return this->is_abstract_; }
-
- // The number of bits.
- int
- bits() const
- { return this->bits_; }
-
- // Whether this type is the same as T.
- bool
- is_identical(const Float_type* t) const;
-
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string*) const;
-
- private:
- Float_type(bool is_abstract, int bits, int runtime_type_kind)
- : Type(TYPE_FLOAT),
- is_abstract_(is_abstract), bits_(bits),
- runtime_type_kind_(runtime_type_kind)
- { }
-
- // Map names of float types to the types themselves.
- typedef std::map<std::string, Named_type*> Named_float_types;
- static Named_float_types named_float_types;
-
- // True if this is an abstract type.
- bool is_abstract_;
- // The number of bits in the floating point value.
- int bits_;
- // The runtime type code used in the type descriptor for this type.
- int runtime_type_kind_;
-};
-
-// The type of a complex number.
-
-class Complex_type : public Type
-{
- public:
- // Create a new complex type.
- static Named_type*
- create_complex_type(const char* name, int bits, int runtime_type_kind);
-
- // Look up an existing complex type.
- static Named_type*
- lookup_complex_type(const char* name);
-
- // Create an abstract complex type.
- static Complex_type*
- create_abstract_complex_type();
-
- // Whether this is an abstract complex type.
- bool
- is_abstract() const
- { return this->is_abstract_; }
-
- // The number of bits: 64 or 128.
- int bits() const
- { return this->bits_; }
-
- // Whether this type is the same as T.
- bool
- is_identical(const Complex_type* t) const;
-
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string*) const;
-
- private:
- Complex_type(bool is_abstract, int bits, int runtime_type_kind)
- : Type(TYPE_COMPLEX),
- is_abstract_(is_abstract), bits_(bits),
- runtime_type_kind_(runtime_type_kind)
- { }
-
- // Map names of complex types to the types themselves.
- typedef std::map<std::string, Named_type*> Named_complex_types;
- static Named_complex_types named_complex_types;
-
- // True if this is an abstract type.
- bool is_abstract_;
- // The number of bits in the complex value--64 or 128.
- int bits_;
- // The runtime type code used in the type descriptor for this type.
- int runtime_type_kind_;
-};
-
-// The type of a string.
-
-class String_type : public Type
-{
- public:
- String_type()
- : Type(TYPE_STRING)
- { }
-
- // Return a tree for the length of STRING.
- static tree
- length_tree(Gogo*, tree string);
-
- // Return a tree which points to the bytes of STRING.
- static tree
- bytes_tree(Gogo*, tree string);
-
- protected:
- bool
- do_has_pointer() const
- { return true; }
-
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string* ret) const;
-
- private:
- // The named string type.
- static Named_type* string_type_;
-};
-
-// The type of a function.
-
-class Function_type : public Type
-{
- public:
- Function_type(Typed_identifier* receiver, Typed_identifier_list* parameters,
- Typed_identifier_list* results, Location location)
- : Type(TYPE_FUNCTION),
- receiver_(receiver), parameters_(parameters), results_(results),
- location_(location), is_varargs_(false), is_builtin_(false)
- { }
-
- // Get the receiver.
- const Typed_identifier*
- receiver() const
- { return this->receiver_; }
-
- // Get the return names and types.
- const Typed_identifier_list*
- results() const
- { return this->results_; }
-
- // Get the parameter names and types.
- const Typed_identifier_list*
- parameters() const
- { return this->parameters_; }
-
- // Whether this is a varargs function.
- bool
- is_varargs() const
- { return this->is_varargs_; }
-
- // Whether this is a builtin function.
- bool
- is_builtin() const
- { return this->is_builtin_; }
-
- // The location where this type was defined.
- Location
- location() const
- { return this->location_; }
-
- // Return whether this is a method type.
- bool
- is_method() const
- { return this->receiver_ != NULL; }
-
- // Whether T is a valid redeclaration of this type. This is called
- // when a function is declared more than once.
- bool
- is_valid_redeclaration(const Function_type* t, std::string*) const;
-
- // Whether this type is the same as T.
- bool
- is_identical(const Function_type* t, bool ignore_receiver,
- bool errors_are_identical, std::string*) const;
-
- // Record that this is a varargs function.
- void
- set_is_varargs()
- { this->is_varargs_ = true; }
-
- // Record that this is a builtin function.
- void
- set_is_builtin()
- { this->is_builtin_ = true; }
-
- // Import a function type.
- static Function_type*
- do_import(Import*);
-
- // Return a copy of this type without a receiver. This is only
- // valid for a method type.
- Function_type*
- copy_without_receiver() const;
-
- // Return a copy of this type with a receiver. This is used when an
- // interface method is attached to a named or struct type.
- Function_type*
- copy_with_receiver(Type*) const;
-
- static Type*
- make_function_type_descriptor_type();
-
- protected:
- int
- do_traverse(Traverse*);
-
- // A trampoline function has a pointer which matters for GC.
- bool
- do_has_pointer() const
- { return true; }
-
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string*) const;
-
- void
- do_export(Export*) const;
-
- private:
- Expression*
- type_descriptor_params(Type*, const Typed_identifier*,
- const Typed_identifier_list*);
-
- // The receiver name and type. This will be NULL for a normal
- // function, non-NULL for a method.
- Typed_identifier* receiver_;
- // The parameter names and types.
- Typed_identifier_list* parameters_;
- // The result names and types. This will be NULL if no result was
- // specified.
- Typed_identifier_list* results_;
- // The location where this type was defined. This exists solely to
- // give a location for the fields of the struct if this function
- // returns multiple values.
- Location location_;
- // Whether this function takes a variable number of arguments.
- bool is_varargs_;
- // Whether this is a special builtin function which can not simply
- // be called. This is used for len, cap, etc.
- bool is_builtin_;
-};
-
-// The type of a pointer.
-
-class Pointer_type : public Type
-{
- public:
- Pointer_type(Type* to_type)
- : Type(TYPE_POINTER),
- to_type_(to_type)
- {}
-
- Type*
- points_to() const
- { return this->to_type_; }
-
- // Import a pointer type.
- static Pointer_type*
- do_import(Import*);
-
- static Type*
- make_pointer_type_descriptor_type();
-
- protected:
- int
- do_traverse(Traverse*);
-
- bool
- do_has_pointer() const
- { return true; }
-
- bool
- do_compare_is_identity(Gogo*)
- { return true; }
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string*) const;
-
- void
- do_export(Export*) const;
-
- private:
- // The type to which this type points.
- Type* to_type_;
-};
-
-// The type of a field in a struct.
-
-class Struct_field
-{
- public:
- explicit Struct_field(const Typed_identifier& typed_identifier)
- : typed_identifier_(typed_identifier), tag_(NULL)
- { }
-
- // The field name.
- const std::string&
- field_name() const;
-
- // Return whether this struct field is named NAME.
- bool
- is_field_name(const std::string& name) const;
-
- // The field type.
- Type*
- type() const
- { return this->typed_identifier_.type(); }
-
- // The field location.
- Location
- location() const
- { return this->typed_identifier_.location(); }
-
- // Whether the field has a tag.
- bool
- has_tag() const
- { return this->tag_ != NULL; }
-
- // The tag.
- const std::string&
- tag() const
- {
- go_assert(this->tag_ != NULL);
- return *this->tag_;
- }
-
- // Whether this is an anonymous field.
- bool
- is_anonymous() const
- { return this->typed_identifier_.name().empty(); }
-
- // Set the tag. FIXME: This is never freed.
- void
- set_tag(const std::string& tag)
- { this->tag_ = new std::string(tag); }
-
- // Set the type. This is only used in error cases.
- void
- set_type(Type* type)
- { this->typed_identifier_.set_type(type); }
-
- private:
- // The field name, type, and location.
- Typed_identifier typed_identifier_;
- // The field tag. This is NULL if the field has no tag.
- std::string* tag_;
-};
-
-// A list of struct fields.
-
-class Struct_field_list
-{
- public:
- Struct_field_list()
- : entries_()
- { }
-
- // Whether the list is empty.
- bool
- empty() const
- { return this->entries_.empty(); }
-
- // Return the number of entries.
- size_t
- size() const
- { return this->entries_.size(); }
-
- // Add an entry to the end of the list.
- void
- push_back(const Struct_field& sf)
- { this->entries_.push_back(sf); }
-
- // Index into the list.
- const Struct_field&
- at(size_t i) const
- { return this->entries_.at(i); }
-
- // Last entry in list.
- Struct_field&
- back()
- { return this->entries_.back(); }
-
- // Iterators.
-
- typedef std::vector<Struct_field>::iterator iterator;
- typedef std::vector<Struct_field>::const_iterator const_iterator;
-
- iterator
- begin()
- { return this->entries_.begin(); }
-
- const_iterator
- begin() const
- { return this->entries_.begin(); }
-
- iterator
- end()
- { return this->entries_.end(); }
-
- const_iterator
- end() const
- { return this->entries_.end(); }
-
- private:
- std::vector<Struct_field> entries_;
-};
-
-// The type of a struct.
-
-class Struct_type : public Type
-{
- public:
- Struct_type(Struct_field_list* fields, Location location)
- : Type(TYPE_STRUCT),
- fields_(fields), location_(location), all_methods_(NULL),
- interface_method_tables_(NULL), pointer_interface_method_tables_(NULL)
- { }
-
- // Return the field NAME. This only looks at local fields, not at
- // embedded types. If the field is found, and PINDEX is not NULL,
- // this sets *PINDEX to the field index. If the field is not found,
- // this returns NULL.
- const Struct_field*
- find_local_field(const std::string& name, unsigned int *pindex) const;
-
- // Return the field number INDEX.
- const Struct_field*
- field(unsigned int index) const
- { return &this->fields_->at(index); }
-
- // Get the struct fields.
- const Struct_field_list*
- fields() const
- { return this->fields_; }
-
- // Return the number of fields.
- size_t
- field_count() const
- { return this->fields_->size(); }
-
- // Push a new field onto the end of the struct. This is used when
- // building a closure variable.
- void
- push_field(const Struct_field& sf)
- { this->fields_->push_back(sf); }
-
- // Return an expression referring to field NAME in STRUCT_EXPR, or
- // NULL if there is no field with that name.
- Field_reference_expression*
- field_reference(Expression* struct_expr, const std::string& name,
- Location) const;
-
- // Return the total number of fields, including embedded fields.
- // This is the number of values that can appear in a conversion to
- // this type.
- unsigned int
- total_field_count() const;
-
- // Whether this type is identical with T.
- bool
- 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
- // anonymous fields have types with hidden fields.
- bool
- struct_has_hidden_fields(const Named_type* within, std::string*) const;
-
- // Return whether NAME is a local field which is not exported. This
- // is only used for better error reporting.
- bool
- is_unexported_local_field(Gogo*, const std::string& name) const;
-
- // If this is an unnamed struct, build the complete list of methods,
- // including those from anonymous fields, and build methods stubs if
- // needed.
- void
- finalize_methods(Gogo*);
-
- // Return whether this type has any methods. This should only be
- // called after the finalize_methods pass.
- bool
- has_any_methods() const
- { return this->all_methods_ != NULL; }
-
- // Return the methods for tihs type. This should only be called
- // after the finalize_methods pass.
- const Methods*
- methods() const
- { return this->all_methods_; }
-
- // Return the method to use for NAME. This returns NULL if there is
- // no such method or if the method is ambiguous. When it returns
- // NULL, this sets *IS_AMBIGUOUS if the method name is ambiguous.
- Method*
- method_function(const std::string& name, bool* is_ambiguous) const;
-
- // Return a pointer to the interface method table for this type for
- // the interface INTERFACE. If IS_POINTER is true, set the type
- // descriptor to a pointer to this type, otherwise set it to this
- // type.
- tree
- interface_method_table(Gogo*, const Interface_type* interface,
- bool is_pointer);
-
- // Traverse just the field types of a struct type.
- int
- traverse_field_types(Traverse* traverse)
- { return this->do_traverse(traverse); }
-
- // If the offset of field INDEX in the backend implementation can be
- // determined, set *POFFSET to the offset in bytes and return true.
- // Otherwise, return false.
- bool
- backend_field_offset(Gogo*, unsigned int index, unsigned int* poffset);
-
- // Finish the backend representation of all the fields.
- void
- finish_backend_fields(Gogo*);
-
- // Import a struct type.
- static Struct_type*
- do_import(Import*);
-
- static Type*
- make_struct_type_descriptor_type();
-
- // Write the hash function for this type.
- void
- write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*);
-
- // Write the equality function for this type.
- void
- write_equal_function(Gogo*, Named_type*);
-
- protected:
- int
- do_traverse(Traverse*);
-
- bool
- do_verify();
-
- bool
- do_has_pointer() const;
-
- bool
- do_compare_is_identity(Gogo*);
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string*) const;
-
- void
- do_export(Export*) const;
-
- private:
- // Used to merge method sets of identical unnamed structs.
- typedef Unordered_map_hash(Struct_type*, Struct_type*, Type_hash_identical,
- Type_identical) Identical_structs;
-
- static Identical_structs identical_structs;
-
- // Used to avoid infinite loops in field_reference_depth.
- struct Saw_named_type
- {
- Saw_named_type* next;
- Named_type* nt;
- };
-
- Field_reference_expression*
- field_reference_depth(Expression* struct_expr, const std::string& name,
- Location, Saw_named_type*,
- unsigned int* depth) const;
-
- // The fields of the struct.
- Struct_field_list* fields_;
- // The place where the struct was declared.
- Location location_;
- // If this struct is unnamed, a list of methods.
- Methods* all_methods_;
- // A mapping from interfaces to the associated interface method
- // tables for this type. Only used if this struct is unnamed.
- Interface_method_tables* interface_method_tables_;
- // A mapping from interfaces to the associated interface method
- // tables for pointers to this type. Only used if this struct is
- // unnamed.
- Interface_method_tables* pointer_interface_method_tables_;
-};
-
-// The type of an array.
-
-class Array_type : public Type
-{
- public:
- Array_type(Type* element_type, Expression* length)
- : Type(TYPE_ARRAY),
- element_type_(element_type), length_(length), length_tree_(NULL)
- { }
-
- // Return the element type.
- Type*
- element_type() const
- { return this->element_type_; }
-
- // Return the length. This will return NULL for an open array.
- Expression*
- length() const
- { return this->length_; }
-
- // Whether this type is identical with T.
- bool
- is_identical(const Array_type* t, bool errors_are_identical) const;
-
- // Whether this type has any hidden fields.
- bool
- array_has_hidden_fields(const Named_type* within, std::string* reason) const
- { return this->element_type_->has_hidden_fields(within, reason); }
-
- // Return a tree for the pointer to the values in an array.
- tree
- value_pointer_tree(Gogo*, tree array) const;
-
- // Return a tree for the length of an array with this type.
- tree
- length_tree(Gogo*, tree array);
-
- // Return a tree for the capacity of an array with this type.
- tree
- capacity_tree(Gogo*, tree array);
-
- // Import an array type.
- static Array_type*
- do_import(Import*);
-
- // Return the backend representation of the element type.
- Btype*
- get_backend_element(Gogo*, bool use_placeholder);
-
- // Return the backend representation of the length.
- Bexpression*
- get_backend_length(Gogo*);
-
- // Finish the backend representation of the element type.
- void
- finish_backend_element(Gogo*);
-
- static Type*
- make_array_type_descriptor_type();
-
- static Type*
- make_slice_type_descriptor_type();
-
- // Write the hash function for this type.
- void
- write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*);
-
- // Write the equality function for this type.
- void
- write_equal_function(Gogo*, Named_type*);
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- bool
- do_verify();
-
- bool
- do_has_pointer() const
- {
- return this->length_ == NULL || this->element_type_->has_pointer();
- }
-
- bool
- do_compare_is_identity(Gogo*);
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string*) const;
-
- void
- do_export(Export*) const;
-
- private:
- bool
- verify_length();
-
- tree
- get_length_tree(Gogo*);
-
- Expression*
- array_type_descriptor(Gogo*, Named_type*);
-
- Expression*
- slice_type_descriptor(Gogo*, Named_type*);
-
- // The type of elements of the array.
- Type* element_type_;
- // The number of elements. This may be NULL.
- Expression* length_;
- // The length as a tree. We only want to compute this once.
- tree length_tree_;
-};
-
-// The type of a map.
-
-class Map_type : public Type
-{
- public:
- Map_type(Type* key_type, Type* val_type, Location location)
- : Type(TYPE_MAP),
- key_type_(key_type), val_type_(val_type), location_(location)
- { }
-
- // Return the key type.
- Type*
- key_type() const
- { return this->key_type_; }
-
- // Return the value type.
- Type*
- val_type() const
- { return this->val_type_; }
-
- // Whether this type is identical with T.
- bool
- is_identical(const Map_type* t, bool errors_are_identical) const;
-
- // Import a map type.
- static Map_type*
- do_import(Import*);
-
- static Type*
- make_map_type_descriptor_type();
-
- static Type*
- make_map_descriptor_type();
-
- // Build a map descriptor for this type. Return a pointer to it.
- // The location is the location which causes us to need the
- // descriptor.
- tree
- map_descriptor_pointer(Gogo* gogo, Location);
-
- protected:
- int
- do_traverse(Traverse*);
-
- bool
- do_verify();
-
- bool
- do_has_pointer() const
- { return true; }
-
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string*) const;
-
- void
- do_export(Export*) const;
-
- private:
- // Mapping from map types to map descriptors.
- typedef Unordered_map_hash(const Map_type*, Bvariable*, Type_hash_identical,
- Type_identical) Map_descriptors;
- static Map_descriptors map_descriptors;
-
- Bvariable*
- map_descriptor(Gogo*);
-
- // The key type.
- Type* key_type_;
- // The value type.
- Type* val_type_;
- // Where the type was defined.
- Location location_;
-};
-
-// The type of a channel.
-
-class Channel_type : public Type
-{
- public:
- Channel_type(bool may_send, bool may_receive, Type* element_type)
- : Type(TYPE_CHANNEL),
- may_send_(may_send), may_receive_(may_receive),
- element_type_(element_type)
- { go_assert(may_send || may_receive); }
-
- // Whether this channel can send data.
- bool
- may_send() const
- { return this->may_send_; }
-
- // Whether this channel can receive data.
- bool
- may_receive() const
- { return this->may_receive_; }
-
- // The type of the values that may be sent on this channel. This is
- // NULL if any type may be sent.
- Type*
- element_type() const
- { return this->element_type_; }
-
- // Whether this type is identical with T.
- bool
- is_identical(const Channel_type* t, bool errors_are_identical) const;
-
- // Import a channel type.
- static Channel_type*
- do_import(Import*);
-
- static Type*
- make_chan_type_descriptor_type();
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Type::traverse(this->element_type_, traverse); }
-
- bool
- do_has_pointer() const
- { return true; }
-
- bool
- do_compare_is_identity(Gogo*)
- { return true; }
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string*) const;
-
- void
- do_export(Export*) const;
-
- private:
- // Whether this channel can send data.
- bool may_send_;
- // Whether this channel can receive data.
- bool may_receive_;
- // The types of elements which may be sent on this channel. If this
- // is NULL, it means that any type may be sent.
- Type* element_type_;
-};
-
-// An interface type.
-
-class Interface_type : public Type
-{
- public:
- Interface_type(Typed_identifier_list* methods, Location location)
- : Type(TYPE_INTERFACE),
- parse_methods_(methods), all_methods_(NULL), location_(location),
- interface_btype_(NULL), assume_identical_(NULL),
- methods_are_finalized_(false), seen_(false)
- { go_assert(methods == NULL || !methods->empty()); }
-
- // The location where the interface type was defined.
- Location
- location() const
- { return this->location_; }
-
- // Return whether this is an empty interface.
- bool
- is_empty() const
- {
- go_assert(this->methods_are_finalized_);
- return this->all_methods_ == NULL;
- }
-
- // Return the list of methods. This will return NULL for an empty
- // interface.
- const Typed_identifier_list*
- methods() const;
-
- // Return the number of methods.
- size_t
- method_count() const;
-
- // Return the method NAME, or NULL.
- const Typed_identifier*
- find_method(const std::string& name) const;
-
- // Return the zero-based index of method NAME.
- size_t
- method_index(const std::string& name) const;
-
- // Finalize the methods. This sets all_methods_. This handles
- // interface inheritance.
- void
- finalize_methods();
-
- // Return true if T implements this interface. If this returns
- // false, and REASON is not NULL, it sets *REASON to the reason that
- // it fails.
- bool
- implements_interface(const Type* t, std::string* reason) const;
-
- // Whether this type is identical with T. REASON is as in
- // implements_interface.
- bool
- 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.
- bool
- is_compatible_for_assign(const Interface_type*, std::string* reason) const;
-
- // Return whether NAME is a method which is not exported. This is
- // only used for better error reporting.
- bool
- is_unexported_method(Gogo*, const std::string& name) const;
-
- // Import an interface type.
- static Interface_type*
- do_import(Import*);
-
- // Make a struct for an empty interface type.
- static Btype*
- get_backend_empty_interface_type(Gogo*);
-
- // Finish the backend representation of the method types.
- void
- finish_backend_methods(Gogo*);
-
- static Type*
- make_interface_type_descriptor_type();
-
- protected:
- int
- do_traverse(Traverse*);
-
- bool
- do_has_pointer() const
- { return true; }
-
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string*) const;
-
- void
- do_export(Export*) const;
-
- private:
- // This type guards against infinite recursion when comparing
- // interface types. We keep a list of interface types assumed to be
- // identical during comparison. We just keep the list on the stack.
- // This permits us to compare cases like
- // type I1 interface { F() interface{I1} }
- // type I2 interface { F() interface{I2} }
- struct Assume_identical
- {
- Assume_identical* next;
- const Interface_type* t1;
- const Interface_type* t2;
- };
-
- bool
- assume_identical(const Interface_type*, const Interface_type*) const;
-
- // The list of methods associated with the interface from the
- // parser. This will be NULL for the empty interface. This may
- // include unnamed interface types.
- Typed_identifier_list* parse_methods_;
- // The list of all methods associated with the interface. This
- // expands any interface types listed in methods_. It is set by
- // finalize_methods. This will be NULL for the empty interface.
- Typed_identifier_list* all_methods_;
- // The location where the interface was defined.
- Location location_;
- // The backend representation of this type during backend conversion.
- Btype* interface_btype_;
- // A list of interface types assumed to be identical during
- // interface comparison.
- mutable Assume_identical* assume_identical_;
- // Whether the methods have been finalized.
- bool methods_are_finalized_;
- // Used to avoid endless recursion in do_mangled_name.
- mutable bool seen_;
-};
-
-// The value we keep for a named type. This lets us get the right
-// name when we convert to trees. Note that we don't actually keep
-// the name here; the name is in the Named_object which points to
-// this. This object exists to hold a unique tree which represents
-// the type.
-
-class Named_type : public Type
-{
- public:
- Named_type(Named_object* named_object, Type* type, Location location)
- : Type(TYPE_NAMED),
- named_object_(named_object), in_function_(NULL), in_function_index_(0),
- type_(type), local_methods_(NULL), all_methods_(NULL),
- interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
- location_(location), named_btype_(NULL), dependencies_(),
- is_visible_(true), is_error_(false), is_placeholder_(false),
- is_converted_(false), is_circular_(false), is_verified_(false),
- seen_(false), seen_in_compare_is_identity_(false),
- seen_in_get_backend_(false)
- { }
-
- // Return the associated Named_object. This holds the actual name.
- Named_object*
- named_object()
- { return this->named_object_; }
-
- const Named_object*
- named_object() const
- { return this->named_object_; }
-
- // Set the Named_object. This is used when we see a type
- // declaration followed by a type.
- void
- set_named_object(Named_object* no)
- { this->named_object_ = no; }
-
- // Return the function in which this type is defined. This will
- // return NULL for a type defined in global scope.
- const Named_object*
- in_function(unsigned int *pindex) const
- {
- *pindex = this->in_function_index_;
- return this->in_function_;
- }
-
- // Set the function in which this type is defined.
- void
- set_in_function(Named_object* f, unsigned int index)
- {
- this->in_function_ = f;
- this->in_function_index_ = index;
- }
-
- // Return the name of the type.
- const std::string&
- name() const;
-
- // Return the name of the type for an error message. The difference
- // is that if the type is defined in a different package, this will
- // return PACKAGE.NAME.
- std::string
- message_name() const;
-
- // Return the underlying type.
- Type*
- real_type()
- { return this->type_; }
-
- const Type*
- real_type() const
- { return this->type_; }
-
- // Return the location.
- Location
- location() const
- { return this->location_; }
-
- // Whether this type is visible. This only matters when parsing.
- bool
- is_visible() const
- { return this->is_visible_; }
-
- // Mark this type as visible.
- void
- set_is_visible()
- { this->is_visible_ = true; }
-
- // Mark this type as invisible.
- void
- clear_is_visible()
- { this->is_visible_ = false; }
-
- // Whether this is a builtin type.
- bool
- is_builtin() const
- { return Linemap::is_predeclared_location(this->location_); }
-
- // Whether this is an alias. There are currently two aliases: byte
- // and rune.
- bool
- is_alias() const;
-
- // Whether this is a circular type: a pointer or function type that
- // refers to itself, which is not possible in C.
- bool
- is_circular() const
- { return this->is_circular_; }
-
- // Return the base type for this type.
- Type*
- named_base();
-
- const Type*
- named_base() const;
-
- // Return whether this is an error type.
- bool
- is_named_error_type() const;
-
- // Return whether this type is comparable. If REASON is not NULL,
- // set *REASON when returning false.
- bool
- named_type_is_comparable(std::string* reason) const;
-
- // Add a method to this type.
- Named_object*
- add_method(const std::string& name, Function*);
-
- // Add a method declaration to this type.
- Named_object*
- add_method_declaration(const std::string& name, Package* package,
- Function_type* type, Location location);
-
- // Add an existing method--one defined before the type itself was
- // defined--to a type.
- void
- add_existing_method(Named_object*);
-
- // Look up a local method.
- Named_object*
- find_local_method(const std::string& name) const;
-
- // Return the list of local methods.
- const Bindings*
- local_methods() const
- { return this->local_methods_; }
-
- // Build the complete list of methods, including those from
- // anonymous fields, and build method stubs if needed.
- void
- finalize_methods(Gogo*);
-
- // Return whether this type has any methods. This should only be
- // called after the finalize_methods pass.
- bool
- has_any_methods() const
- { return this->all_methods_ != NULL; }
-
- // Return the methods for this type. This should only be called
- // after the finalized_methods pass.
- const Methods*
- methods() const
- { return this->all_methods_; }
-
- // Return the method to use for NAME. This returns NULL if there is
- // no such method or if the method is ambiguous. When it returns
- // NULL, this sets *IS_AMBIGUOUS if the method name is ambiguous.
- Method*
- method_function(const std::string& name, bool *is_ambiguous) const;
-
- // Return whether NAME is a known field or method which is not
- // exported. This is only used for better error reporting.
- bool
- is_unexported_local_method(Gogo*, const std::string& name) const;
-
- // Return a pointer to the interface method table for this type for
- // the interface INTERFACE. If IS_POINTER is true, set the type
- // descriptor to a pointer to this type, otherwise set it to this
- // type.
- tree
- interface_method_table(Gogo*, const Interface_type* interface,
- bool is_pointer);
-
- // Whether this type has any hidden fields.
- bool
- named_type_has_hidden_fields(std::string* reason) const;
-
- // Note that a type must be converted to the backend representation
- // before we convert this type.
- void
- add_dependency(Named_type* nt)
- { this->dependencies_.push_back(nt); }
-
- // Return true if the size and alignment of the backend
- // representation of this type is known. This is always true after
- // types have been converted, but may be false beforehand.
- bool
- is_named_backend_type_size_known() const
- { return this->named_btype_ != NULL && !this->is_placeholder_; }
-
- // Export the type.
- void
- export_named_type(Export*, const std::string& name) const;
-
- // Import a named type.
- static void
- import_named_type(Import*, Named_type**);
-
- // Initial conversion to backend representation.
- void
- convert(Gogo*);
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Type::traverse(this->type_, traverse); }
-
- bool
- do_verify();
-
- bool
- do_has_pointer() const;
-
- bool
- do_compare_is_identity(Gogo*);
-
- unsigned int
- do_hash_for_method(Gogo*) const;
-
- Btype*
- do_get_backend(Gogo*);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string* ret) const;
-
- void
- do_export(Export*) const;
-
- private:
- // Create the placeholder during conversion.
- void
- create_placeholder(Gogo*);
-
- // A pointer back to the Named_object for this type.
- Named_object* named_object_;
- // If this type is defined in a function, a pointer back to the
- // function in which it is defined.
- Named_object* in_function_;
- // The index of this type in IN_FUNCTION_.
- unsigned int in_function_index_;
- // The actual type.
- Type* type_;
- // The list of methods defined for this type. Any named type can
- // have methods.
- Bindings* local_methods_;
- // The full list of methods for this type, including methods
- // declared for anonymous fields.
- Methods* all_methods_;
- // A mapping from interfaces to the associated interface method
- // tables for this type.
- Interface_method_tables* interface_method_tables_;
- // A mapping from interfaces to the associated interface method
- // tables for pointers to this type.
- Interface_method_tables* pointer_interface_method_tables_;
- // The location where this type was defined.
- Location location_;
- // The backend representation of this type during backend
- // conversion. This is used to avoid endless recursion when a named
- // type refers to itself.
- Btype* named_btype_;
- // A list of types which must be converted to the backend
- // representation before this type can be converted. This is for
- // cases like
- // type S1 { p *S2 }
- // type S2 { s S1 }
- // where we can't convert S2 to the backend representation unless we
- // have converted S1.
- std::vector<Named_type*> dependencies_;
- // Whether this type is visible. This is false if this type was
- // created because it was referenced by an imported object, but the
- // type itself was not exported. This will always be true for types
- // created in the current package.
- bool is_visible_;
- // Whether this type is erroneous.
- bool is_error_;
- // Whether the current value of named_btype_ is a placeholder for
- // which the final size of the type is not known.
- bool is_placeholder_;
- // Whether this type has been converted to the backend
- // representation. Implies that is_placeholder_ is false.
- bool is_converted_;
- // Whether this is a pointer or function type which refers to the
- // type itself.
- bool is_circular_;
- // Whether this type has been verified.
- bool is_verified_;
- // In a recursive operation such as has_hidden_fields, this flag is
- // used to prevent infinite recursion when a type refers to itself.
- // This is mutable because it is always reset to false when the
- // function exits.
- mutable bool seen_;
- // Like seen_, but used only by do_compare_is_identity.
- bool seen_in_compare_is_identity_;
- // Like seen_, but used only by do_get_backend.
- bool seen_in_get_backend_;
-};
-
-// A forward declaration. This handles a type which has been declared
-// but not defined.
-
-class Forward_declaration_type : public Type
-{
- public:
- Forward_declaration_type(Named_object* named_object);
-
- // The named object associated with this type declaration. This
- // will be resolved.
- Named_object*
- named_object();
-
- const Named_object*
- named_object() const;
-
- // Return the name of the type.
- const std::string&
- name() const;
-
- // Return the type to which this points. Give an error if the type
- // has not yet been defined.
- Type*
- real_type();
-
- const Type*
- real_type() const;
-
- // Whether the base type has been defined.
- bool
- is_defined() const;
-
- // Add a method to this type.
- Named_object*
- add_method(const std::string& name, Function*);
-
- // Add a method declaration to this type.
- Named_object*
- add_method_declaration(const std::string& name, Package*, Function_type*,
- Location);
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- bool
- do_verify();
-
- bool
- do_has_pointer() const
- { return this->real_type()->has_pointer(); }
-
- bool
- do_compare_is_identity(Gogo* gogo)
- { return this->real_type()->compare_is_identity(gogo); }
-
- unsigned int
- do_hash_for_method(Gogo* gogo) const
- { return this->real_type()->hash_for_method(gogo); }
-
- Btype*
- do_get_backend(Gogo* gogo);
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*);
-
- void
- do_reflection(Gogo*, std::string*) const;
-
- void
- do_mangled_name(Gogo*, std::string* ret) const;
-
- void
- do_export(Export*) const;
-
- private:
- // Issue a warning about a use of an undefined type.
- void
- warn() const;
-
- // The type declaration.
- Named_object* named_object_;
- // Whether we have issued a warning about this type.
- mutable bool warned_;
-};
-
-// The Type_context struct describes what we expect for the type of an
-// expression.
-
-struct Type_context
-{
- // The exact type we expect, if known. This may be NULL.
- Type* type;
- // Whether an abstract type is permitted.
- bool may_be_abstract;
-
- // Constructors.
- Type_context()
- : type(NULL), may_be_abstract(false)
- { }
-
- Type_context(Type* a_type, bool a_may_be_abstract)
- : type(a_type), may_be_abstract(a_may_be_abstract)
- { }
-};
-
-#endif // !defined(GO_TYPES_H)
diff --git a/gcc-4.8.1/gcc/go/gofrontend/unsafe.cc b/gcc-4.8.1/gcc/go/gofrontend/unsafe.cc
deleted file mode 100644
index e7c61f023..000000000
--- a/gcc-4.8.1/gcc/go/gofrontend/unsafe.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// unsafe.cc -- Go frontend builtin unsafe package.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include "go-c.h"
-#include "types.h"
-#include "gogo.h"
-
-// Set up the builtin unsafe package. This should probably be driven
-// by a table.
-
-void
-Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
- Location location)
-{
- Location bloc = Linemap::predeclared_location();
-
- bool add_to_globals;
- Package* package = this->add_imported_package("unsafe", local_name,
- is_local_name_exported,
- "unsafe", location,
- &add_to_globals);
-
- if (package == NULL)
- {
- go_assert(saw_errors());
- return;
- }
-
- package->set_location(location);
- package->set_is_imported();
-
- this->imports_.insert(std::make_pair("unsafe", package));
-
- Bindings* bindings = package->bindings();
-
- // The type may have already been created by an import.
- Named_object* no = package->bindings()->lookup("Pointer");
- if (no == NULL)
- {
- Type* type = Type::make_pointer_type(Type::make_void_type());
- no = bindings->add_type("Pointer", package, type,
- Linemap::unknown_location());
- }
- else
- {
- go_assert(no->package() == package);
- go_assert(no->is_type());
- go_assert(no->type_value()->is_unsafe_pointer_type());
- no->type_value()->set_is_visible();
- }
- Named_type* pointer_type = no->type_value();
- if (add_to_globals)
- this->add_named_type(pointer_type);
-
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
-
- // Sizeof.
- Typed_identifier_list* results = new Typed_identifier_list;
- results->push_back(Typed_identifier("", uintptr_type, bloc));
- Function_type* fntype = Type::make_function_type(NULL, NULL, results, bloc);
- fntype->set_is_builtin();
- no = bindings->add_function_declaration("Sizeof", package, fntype, bloc);
- if (add_to_globals)
- this->add_named_object(no);
-
- // Offsetof.
- results = new Typed_identifier_list;
- results->push_back(Typed_identifier("", uintptr_type, bloc));
- fntype = Type::make_function_type(NULL, NULL, results, bloc);
- fntype->set_is_varargs();
- fntype->set_is_builtin();
- no = bindings->add_function_declaration("Offsetof", package, fntype, bloc);
- if (add_to_globals)
- this->add_named_object(no);
-
- // Alignof.
- results = new Typed_identifier_list;
- results->push_back(Typed_identifier("", uintptr_type, bloc));
- fntype = Type::make_function_type(NULL, NULL, results, bloc);
- fntype->set_is_varargs();
- fntype->set_is_builtin();
- no = bindings->add_function_declaration("Alignof", package, fntype, bloc);
- if (add_to_globals)
- this->add_named_object(no);
-
- if (!this->imported_unsafe_)
- {
- go_imported_unsafe();
- this->imported_unsafe_ = true;
- }
-}