summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2014-04-14 22:43:47 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2014-04-14 22:43:47 +0000
commit2c809f8f2584460a5207662cc8e064486cb0ec30 (patch)
treeb131f3f58afbe5406406926c7d499bebab24fdf2
parent49209ca7c1a7fc226f3d7705aec7341636a9146c (diff)
downloadgcc-2c809f8f2584460a5207662cc8e064486cb0ec30.tar.gz
Sync to current external repository.
user: Ian Lance Taylor <iant@golang.org> date: Thu Apr 10 09:25:24 2014 -0700 files: go/expressions.cc description: compiler: add checks for constant overflow Prevent extremely large constants from eating all of memory. user: Chris Manghane <cmang@golang.org> date: Mon Apr 07 16:57:09 2014 -0700 files: go/gogo-tree.cc go/gogo.cc go/gogo.h go/statements.cc description: compiler: Use backend interface for variable initialization. user: Chris Manghane <cmang@golang.org> date: Thu Apr 03 19:56:05 2014 -0700 files: go/backend.h go/gogo-tree.cc go/gogo.cc go/gogo.h description: compiler: Use backend interface to build function code. changeset: 1269:6e30875d539e user: Chris Manghane <cmang@golang.org> date: Wed Apr 02 13:16:00 2014 -0700 files: go/backend.h go/gogo-tree.cc go/gogo.cc go/gogo.h description: compiler: Use backend interface for building function defer wrappers. user: Chris Manghane <cmang@golang.org> date: Mon Mar 31 12:42:49 2014 -0700 files: go/expressions.cc go/gogo-tree.cc go/gogo.cc go/gogo.h description: compiler: Use backend interface for memory allocation. user: Chris Manghane <cmang@golang.org> date: Thu Mar 27 14:22:49 2014 -0700 files: go/backend.h go/expressions.cc go/expressions.h description: compiler: Use backend interface for fixed array construction. user: Chris Manghane <cmang@golang.org> date: Mon Mar 17 21:25:04 2014 -0700 files: go/expressions.cc description: compiler: Check for loops in self-referential array types. Fixes issue 7525. user: Chris Manghane <cmang@golang.org> date: Mon Mar 17 14:31:59 2014 -0700 files: go/gogo.cc go/parse.cc description: compiler: Don't declare blank labels. Fixes issue 7539. user: Chris Manghane <cmang@golang.org> date: Mon Mar 17 13:12:32 2014 -0700 files: go/backend.h go/expressions.cc go/expressions.h go/runtime.def description: compiler: Use backend interface for call expressions. user: Chris Manghane <cmang@golang.org> date: Wed Mar 12 13:34:27 2014 -0700 files: go/expressions.cc go/expressions.h go/gogo-tree.cc go/statements.cc description: compiler: Use backend interface map construction. user: Chris Manghane <cmang@golang.org> date: Tue Mar 11 12:53:06 2014 -0700 files: go/backend.h go/expressions.cc go/gogo-tree.cc go/gogo.h description: compiler: Use backend interface for string expressions. user: Chris Manghane <cmang@golang.org> date: Sat Mar 08 15:56:59 2014 -0800 files: go/backend.h go/expressions.cc go/expressions.h description: compiler: Use backend interface for array and string indexing. user: Chris Manghane <cmang@golang.org> date: Fri Mar 07 16:02:18 2014 -0800 files: go/expressions.cc description: compiler: Use backend interface for constant expressions. user: Chris Manghane <cmang@golang.org> date: Thu Mar 06 16:00:18 2014 -0800 files: go/expressions.cc description: compiler: Use backend interface for struct construction. user: Chris Manghane <cmang@golang.org> date: Wed Mar 05 13:09:37 2014 -0800 files: go/expressions.cc description: compiler: Use backend interface for type conversions. user: Chris Manghane <cmang@golang.org> date: Tue Mar 04 07:03:47 2014 -0800 files: go/expressions.cc go/expressions.h go/gogo-tree.cc go/gogo.h go/runtime.def libgo/runtime/chan.c description: compiler: Use backend interface for channel receive. user: Chris Manghane <cmang@golang.org> date: Mon Mar 03 15:18:57 2014 -0800 files: go/backend.h go/expressions.cc go/runtime.def description: compiler: Use backend interface for builtin calls. user: Chris Manghane <cmang@golang.org> date: Mon Mar 03 07:44:35 2014 -0800 files: go/expressions.cc go/expressions.h go/types.cc go/types.h description: compiler: Use backend interface for string info. user: Chris Manghane <cmang@golang.org> date: Fri Feb 28 10:45:55 2014 -0800 files: go/expressions.cc go/expressions.h go/gogo-tree.cc go/statements.cc description: compiler: Use backend interface for map indexing. user: Chris Manghane <cmang@golang.org> date: Wed Feb 26 14:13:10 2014 -0800 files: go/expressions.cc go/expressions.h description: compiler: Use backend interface for slice value expressions. user: Chris Manghane <cmang@golang.org> date: Wed Feb 26 13:12:19 2014 -0800 files: go/backend.h go/expressions.cc go/expressions.h go/gogo-tree.cc go/runtime.def go/statements.cc description: compiler: Use backend interface for interface values. user: Chris Manghane <cmang@golang.org> date: Mon Feb 24 12:30:13 2014 -0800 files: go/expressions.cc go/expressions.h go/parse.cc go/statements.cc description: compiler: Change Heap_composite_expression to Heap_expression. user: Chris Manghane <cmang@golang.org> date: Thu Feb 20 19:47:06 2014 -0800 files: go/expressions.cc go/expressions.h go/gogo-tree.cc go/gogo.cc go/gogo.h go/types.cc go/types.h description: compiler: Use backend interface for interface method table expressions. user: Chris Manghane <cmang@golang.org> date: Mon Feb 03 14:36:20 2014 -0800 files: go/expressions.cc go/expressions.h description: compiler: Add compound expressions to the frontend. * go-gcc.cc: Include "convert.h". (Gcc_backend::string_constant_expression): New function. (Gcc_backend::real_part_expression): Likewise. (Gcc_backend::imag_part_expression): Likewise. (Gcc_backend::complex_expression): Likewise. (Gcc_backend::constructor_expression): Likewise. (Gcc_backend::array_constructor_expression): Likewise. (Gcc_backend::pointer_offset_expression): Likewise. (Gcc_backend::array_index_expression): Likewise. (Gcc_backend::call_expression): Likewise. (Gcc_backend::exception_handler_statement): Likewise. (Gcc_backend::function_defer_statement): Likewise. (Gcc_backend::function_set_parameters): Likewise. (Gcc_backend::function_set_body): Likewise. (Gcc_backend::convert_expression): Handle various type conversions. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@209393 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/go/ChangeLog19
-rw-r--r--gcc/go/go-gcc.cc447
-rw-r--r--gcc/go/gofrontend/backend.h77
-rw-r--r--gcc/go/gofrontend/expressions.cc3652
-rw-r--r--gcc/go/gofrontend/expressions.h139
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc924
-rw-r--r--gcc/go/gofrontend/gogo.cc390
-rw-r--r--gcc/go/gofrontend/gogo.h66
-rw-r--r--gcc/go/gofrontend/parse.cc7
-rw-r--r--gcc/go/gofrontend/runtime.def16
-rw-r--r--gcc/go/gofrontend/statements.cc19
-rw-r--r--gcc/go/gofrontend/types.cc69
-rw-r--r--gcc/go/gofrontend/types.h26
-rw-r--r--libgo/runtime/chan.c27
14 files changed, 2991 insertions, 2887 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index 689578e2064..0d153fa02e6 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,22 @@
+2014-04-14 Chris Manghane <cmang@google.com>
+
+ * go-gcc.cc: Include "convert.h".
+ (Gcc_backend::string_constant_expression): New function.
+ (Gcc_backend::real_part_expression): Likewise.
+ (Gcc_backend::imag_part_expression): Likewise.
+ (Gcc_backend::complex_expression): Likewise.
+ (Gcc_backend::constructor_expression): Likewise.
+ (Gcc_backend::array_constructor_expression): Likewise.
+ (Gcc_backend::pointer_offset_expression): Likewise.
+ (Gcc_backend::array_index_expression): Likewise.
+ (Gcc_backend::call_expression): Likewise.
+ (Gcc_backend::exception_handler_statement): Likewise.
+ (Gcc_backend::function_defer_statement): Likewise.
+ (Gcc_backend::function_set_parameters): Likewise.
+ (Gcc_backend::function_set_body): Likewise.
+ (Gcc_backend::convert_expression): Handle various type
+ conversions.
+
2014-03-03 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (Gcc_backend::immutable_struct): If IS_COMMON, set
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 6aec2877d7b..3abefaee9e6 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -29,6 +29,7 @@
#include "stor-layout.h"
#include "varasm.h"
#include "tree-iterator.h"
+#include "convert.h"
#include "basic-block.h"
#include "gimple-expr.h"
#include "toplev.h"
@@ -235,6 +236,18 @@ class Gcc_backend : public Backend
complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag);
Bexpression*
+ string_constant_expression(const std::string& val);
+
+ Bexpression*
+ real_part_expression(Bexpression* bcomplex, Location);
+
+ Bexpression*
+ imag_part_expression(Bexpression* bcomplex, Location);
+
+ Bexpression*
+ complex_expression(Bexpression* breal, Bexpression* bimag, Location);
+
+ Bexpression*
convert_expression(Btype* type, Bexpression* expr, Location);
Bexpression*
@@ -259,6 +272,23 @@ class Gcc_backend : public Backend
Bexpression*
binary_expression(Operator, Bexpression*, Bexpression*, Location);
+ Bexpression*
+ constructor_expression(Btype*, const std::vector<Bexpression*>&, Location);
+
+ Bexpression*
+ array_constructor_expression(Btype*, const std::vector<unsigned long>&,
+ const std::vector<Bexpression*>&, Location);
+
+ Bexpression*
+ pointer_offset_expression(Bexpression* base, Bexpression* offset, Location);
+
+ Bexpression*
+ array_index_expression(Bexpression* array, Bexpression* index, Location);
+
+ Bexpression*
+ call_expression(Bexpression* fn, const std::vector<Bexpression*>& args,
+ Location);
+
// Statements.
Bstatement*
@@ -294,6 +324,10 @@ class Gcc_backend : public Backend
Bstatement*
statement_list(const std::vector<Bstatement*>&);
+ Bstatement*
+ exception_handler_statement(Bstatement* bstat, Bstatement* except_stmt,
+ Bstatement* finally_stmt, Location);
+
// Blocks.
Bblock*
@@ -372,6 +406,16 @@ class Gcc_backend : public Backend
bool is_visible, bool is_declaration, bool is_inlinable,
bool disable_split_stack, bool in_unique_section, Location);
+ Bstatement*
+ function_defer_statement(Bfunction* function, Bexpression* undefer,
+ Bexpression* defer, Location);
+
+ bool
+ function_set_parameters(Bfunction* function, const std::vector<Bvariable*>&);
+
+ bool
+ function_set_body(Bfunction* function, Bstatement* code_stmt);
+
private:
// Make a Bexpression from a tree.
Bexpression*
@@ -974,18 +1018,108 @@ Gcc_backend::complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag)
return tree_to_expr(ret);
}
+// Make a constant string expression.
+
+Bexpression*
+Gcc_backend::string_constant_expression(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 this->make_expression(string_val);
+}
+
+// Return the real part of a complex expression.
+
+Bexpression*
+Gcc_backend::real_part_expression(Bexpression* bcomplex, Location location)
+{
+ tree complex_tree = bcomplex->get_tree();
+ if (complex_tree == error_mark_node)
+ return this->error_expression();
+ gcc_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(complex_tree)));
+ tree ret = fold_build1_loc(location.gcc_location(), REALPART_EXPR,
+ TREE_TYPE(TREE_TYPE(complex_tree)),
+ complex_tree);
+ return this->make_expression(ret);
+}
+
+// Return the imaginary part of a complex expression.
+
+Bexpression*
+Gcc_backend::imag_part_expression(Bexpression* bcomplex, Location location)
+{
+ tree complex_tree = bcomplex->get_tree();
+ if (complex_tree == error_mark_node)
+ return this->error_expression();
+ gcc_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(complex_tree)));
+ tree ret = fold_build1_loc(location.gcc_location(), IMAGPART_EXPR,
+ TREE_TYPE(TREE_TYPE(complex_tree)),
+ complex_tree);
+ return this->make_expression(ret);
+}
+
+// Make a complex expression given its real and imaginary parts.
+
+Bexpression*
+Gcc_backend::complex_expression(Bexpression* breal, Bexpression* bimag,
+ Location location)
+{
+ tree real_tree = breal->get_tree();
+ tree imag_tree = bimag->get_tree();
+ if (real_tree == error_mark_node || imag_tree == error_mark_node)
+ return this->error_expression();
+ gcc_assert(TYPE_MAIN_VARIANT(TREE_TYPE(real_tree))
+ == TYPE_MAIN_VARIANT(TREE_TYPE(imag_tree)));
+ gcc_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(real_tree)));
+ tree ret = fold_build2_loc(location.gcc_location(), COMPLEX_EXPR,
+ build_complex_type(TREE_TYPE(real_tree)),
+ real_tree, imag_tree);
+ return this->make_expression(ret);
+}
+
// An expression that converts an expression to a different type.
Bexpression*
-Gcc_backend::convert_expression(Btype* type, Bexpression* expr, Location)
+Gcc_backend::convert_expression(Btype* type, Bexpression* expr,
+ Location location)
{
tree type_tree = type->get_tree();
tree expr_tree = expr->get_tree();
- if (type_tree == error_mark_node || expr_tree == error_mark_node)
+ if (type_tree == error_mark_node
+ || expr_tree == error_mark_node
+ || TREE_TYPE(expr_tree) == error_mark_node)
return this->error_expression();
- tree ret = fold_convert(type_tree, expr_tree);
- return tree_to_expr(ret);
+ tree ret;
+ if (this->type_size(type) == 0)
+ {
+ // Do not convert zero-sized types.
+ ret = expr_tree;
+ }
+ else if (TREE_CODE(type_tree) == INTEGER_TYPE)
+ ret = fold(convert_to_integer(type_tree, expr_tree));
+ else if (TREE_CODE(type_tree) == REAL_TYPE)
+ ret = fold(convert_to_real(type_tree, expr_tree));
+ else if (TREE_CODE(type_tree) == COMPLEX_TYPE)
+ ret = fold(convert_to_complex(type_tree, expr_tree));
+ else if (TREE_CODE(type_tree) == POINTER_TYPE
+ && TREE_CODE(TREE_TYPE(expr_tree)) == INTEGER_TYPE)
+ ret = fold(convert_to_pointer(type_tree, expr_tree));
+ else if (TREE_CODE(type_tree) == RECORD_TYPE
+ || TREE_CODE(type_tree) == ARRAY_TYPE)
+ ret = fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR,
+ type_tree, expr_tree);
+ else
+ ret = fold_convert_loc(location.gcc_location(), type_tree, expr_tree);
+
+ return this->make_expression(ret);
}
// Get the address of a function.
@@ -1243,6 +1377,205 @@ Gcc_backend::binary_expression(Operator op, Bexpression* left,
return this->make_expression(ret);
}
+// Return an expression that constructs BTYPE with VALS.
+
+Bexpression*
+Gcc_backend::constructor_expression(Btype* btype,
+ const std::vector<Bexpression*>& vals,
+ Location location)
+{
+ tree type_tree = btype->get_tree();
+ if (type_tree == error_mark_node)
+ return this->error_expression();
+
+ vec<constructor_elt, va_gc> *init;
+ vec_alloc(init, vals.size());
+
+ bool is_constant = true;
+ tree field = TYPE_FIELDS(type_tree);
+ for (std::vector<Bexpression*>::const_iterator p = vals.begin();
+ p != vals.end();
+ ++p, field = DECL_CHAIN(field))
+ {
+ gcc_assert(field != NULL_TREE);
+ tree val = (*p)->get_tree();
+ if (TREE_TYPE(field) == error_mark_node
+ || val == error_mark_node
+ || TREE_TYPE(val) == error_mark_node)
+ return this->error_expression();
+
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt* elt = init->quick_push(empty);
+ elt->index = field;
+ elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
+ val);
+ if (!TREE_CONSTANT(elt->value))
+ is_constant = false;
+ }
+ gcc_assert(field == NULL_TREE);
+ tree ret = build_constructor(type_tree, init);
+ if (is_constant)
+ TREE_CONSTANT(ret) = 1;
+
+ return this->make_expression(ret);
+}
+
+Bexpression*
+Gcc_backend::array_constructor_expression(
+ Btype* array_btype, const std::vector<unsigned long>& indexes,
+ const std::vector<Bexpression*>& vals, Location)
+{
+ tree type_tree = array_btype->get_tree();
+ if (type_tree == error_mark_node)
+ return this->error_expression();
+
+ gcc_assert(indexes.size() == vals.size());
+ vec<constructor_elt, va_gc> *init;
+ vec_alloc(init, vals.size());
+
+ bool is_constant = true;
+ for (size_t i = 0; i < vals.size(); ++i)
+ {
+ tree index = size_int(indexes[i]);
+ tree val = (vals[i])->get_tree();
+
+ if (index == error_mark_node
+ || val == error_mark_node)
+ return this->error_expression();
+
+ if (!TREE_CONSTANT(val))
+ is_constant = false;
+
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt* elt = init->quick_push(empty);
+ elt->index = index;
+ elt->value = val;
+ }
+
+ tree ret = build_constructor(type_tree, init);
+ if (is_constant)
+ TREE_CONSTANT(ret) = 1;
+ return this->make_expression(ret);
+}
+
+// Return an expression for the address of BASE[INDEX].
+
+Bexpression*
+Gcc_backend::pointer_offset_expression(Bexpression* base, Bexpression* index,
+ Location location)
+{
+ tree base_tree = base->get_tree();
+ tree index_tree = index->get_tree();
+ tree element_type_tree = TREE_TYPE(TREE_TYPE(base_tree));
+ if (base_tree == error_mark_node
+ || TREE_TYPE(base_tree) == error_mark_node
+ || index_tree == error_mark_node
+ || element_type_tree == error_mark_node)
+ return this->error_expression();
+
+ tree element_size = TYPE_SIZE_UNIT(element_type_tree);
+ index_tree = fold_convert_loc(location.gcc_location(), sizetype, index_tree);
+ tree offset = fold_build2_loc(location.gcc_location(), MULT_EXPR, sizetype,
+ index_tree, element_size);
+ tree ptr = fold_build2_loc(location.gcc_location(), POINTER_PLUS_EXPR,
+ TREE_TYPE(base_tree), base_tree, offset);
+ return this->make_expression(ptr);
+}
+
+// Return an expression representing ARRAY[INDEX]
+
+Bexpression*
+Gcc_backend::array_index_expression(Bexpression* array, Bexpression* index,
+ Location location)
+{
+ tree array_tree = array->get_tree();
+ tree index_tree = index->get_tree();
+ if (array_tree == error_mark_node
+ || TREE_TYPE(array_tree) == error_mark_node
+ || index_tree == error_mark_node)
+ return this->error_expression();
+
+ tree ret = build4_loc(location.gcc_location(), ARRAY_REF,
+ TREE_TYPE(TREE_TYPE(array_tree)), array_tree,
+ index_tree, NULL_TREE, NULL_TREE);
+ return this->make_expression(ret);
+}
+
+// Create an expression for a call to FN_EXPR with FN_ARGS.
+Bexpression*
+Gcc_backend::call_expression(Bexpression* fn_expr,
+ const std::vector<Bexpression*>& fn_args,
+ Location location)
+{
+ tree fn = fn_expr->get_tree();
+ if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
+ return this->error_expression();
+
+ gcc_assert(FUNCTION_POINTER_TYPE_P(TREE_TYPE(fn)));
+ tree rettype = TREE_TYPE(TREE_TYPE(TREE_TYPE(fn)));
+
+ size_t nargs = fn_args.size();
+ tree* args = nargs == 0 ? NULL : new tree[nargs];
+ for (size_t i = 0; i < nargs; ++i)
+ {
+ args[i] = fn_args.at(i)->get_tree();
+ if (args[i] == error_mark_node)
+ return this->error_expression();
+ }
+
+ tree fndecl = fn;
+ if (TREE_CODE(fndecl) == ADDR_EXPR)
+ fndecl = TREE_OPERAND(fndecl, 0);
+
+ // 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 (size_t 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]);
+ }
+ }
+ }
+ }
+
+ tree ret =
+ build_call_array_loc(location.gcc_location(),
+ excess_type != NULL_TREE ? excess_type : rettype,
+ fn, nargs, args);
+
+ 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_loc(location.gcc_location(), NOP_EXPR, rettype, ret);
+ }
+
+ delete[] args;
+ return this->make_expression(ret);
+}
+
// An expression as a statement.
Bstatement*
@@ -1402,6 +1735,40 @@ Gcc_backend::return_statement(Bfunction* bfunction,
return this->make_statement(ret);
}
+// Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if an
+// error occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and if not
+// NULL, it will always be executed. This is used for handling defers in Go
+// functions. In C++, the resulting code is of this form:
+// try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; }
+
+Bstatement*
+Gcc_backend::exception_handler_statement(Bstatement* bstat,
+ Bstatement* except_stmt,
+ Bstatement* finally_stmt,
+ Location location)
+{
+ tree stat_tree = bstat->get_tree();
+ tree except_tree = except_stmt == NULL ? NULL_TREE : except_stmt->get_tree();
+ tree finally_tree = finally_stmt == NULL
+ ? NULL_TREE
+ : finally_stmt->get_tree();
+
+ if (stat_tree == error_mark_node
+ || except_tree == error_mark_node
+ || finally_tree == error_mark_node)
+ return this->error_statement();
+
+ if (except_tree != NULL_TREE)
+ stat_tree = build2_loc(location.gcc_location(), TRY_CATCH_EXPR,
+ void_type_node, stat_tree,
+ build2_loc(location.gcc_location(), CATCH_EXPR,
+ void_type_node, NULL, except_tree));
+ if (finally_tree != NULL_TREE)
+ stat_tree = build2_loc(location.gcc_location(), TRY_FINALLY_EXPR,
+ void_type_node, stat_tree, finally_tree);
+ return this->make_statement(stat_tree);
+}
+
// If.
Bstatement*
@@ -2070,6 +2437,78 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
return new Bfunction(decl);
}
+// Create a statement that runs all deferred calls for FUNCTION. This should
+// be a statement that looks like this in C++:
+// finish:
+// try { UNDEFER; } catch { CHECK_DEFER; goto finish; }
+
+Bstatement*
+Gcc_backend::function_defer_statement(Bfunction* function, Bexpression* undefer,
+ Bexpression* defer, Location location)
+{
+ tree undefer_tree = undefer->get_tree();
+ tree defer_tree = defer->get_tree();
+
+ if (undefer_tree == error_mark_node
+ || defer_tree == error_mark_node)
+ return this->error_statement();
+
+ tree stmt_list = NULL;
+ Blabel* blabel = this->label(function, "", location);
+ Bstatement* label_def = this->label_definition_statement(blabel);
+ append_to_statement_list(label_def->get_tree(), &stmt_list);
+
+ Bstatement* jump_stmt = this->goto_statement(blabel, location);
+ tree jump = jump_stmt->get_tree();
+ tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer_tree, jump);
+ catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body);
+ tree try_catch =
+ build2(TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body);
+ append_to_statement_list(try_catch, &stmt_list);
+
+ return this->make_statement(stmt_list);
+}
+
+// Record PARAM_VARS as the variables to use for the parameters of FUNCTION.
+// This will only be called for a function definition.
+
+bool
+Gcc_backend::function_set_parameters(Bfunction* function,
+ const std::vector<Bvariable*>& param_vars)
+{
+ tree func_tree = function->get_tree();
+ if (func_tree == error_mark_node)
+ return false;
+
+ tree params = NULL_TREE;
+ tree *pp = &params;
+ for (std::vector<Bvariable*>::const_iterator pv = param_vars.begin();
+ pv != param_vars.end();
+ ++pv)
+ {
+ *pp = (*pv)->get_tree();
+ gcc_assert(*pp != error_mark_node);
+ pp = &DECL_CHAIN(*pp);
+ }
+ *pp = NULL_TREE;
+ DECL_ARGUMENTS(func_tree) = params;
+ return true;
+}
+
+// Set the function body for FUNCTION using the code in CODE_BLOCK.
+
+bool
+Gcc_backend::function_set_body(Bfunction* function, Bstatement* code_stmt)
+{
+ tree func_tree = function->get_tree();
+ tree code = code_stmt->get_tree();
+
+ if (func_tree == error_mark_node || code == error_mark_node)
+ return false;
+ DECL_SAVED_TREE(func_tree) = code;
+ return true;
+}
+
// The single backend.
static Gcc_backend gcc_backend;
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index cbe5f22b6ad..fd657ecc989 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -269,6 +269,22 @@ class Backend
virtual Bexpression*
complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag) = 0;
+ // Return an expression for the string value VAL.
+ virtual Bexpression*
+ string_constant_expression(const std::string& val) = 0;
+
+ // Return an expression for the real part of BCOMPLEX.
+ virtual Bexpression*
+ real_part_expression(Bexpression* bcomplex, Location) = 0;
+
+ // Return an expression for the imaginary part of BCOMPLEX.
+ virtual Bexpression*
+ imag_part_expression(Bexpression* bcomplex, Location) = 0;
+
+ // Return an expression for the complex number (BREAL, BIMAG).
+ virtual Bexpression*
+ complex_expression(Bexpression* breal, Bexpression* bimag, Location) = 0;
+
// Return an expression that converts EXPR to TYPE.
virtual Bexpression*
convert_expression(Btype* type, Bexpression* expr, Location) = 0;
@@ -312,6 +328,38 @@ class Backend
binary_expression(Operator op, Bexpression* left, Bexpression* right,
Location) = 0;
+ // Return an expression that constructs BTYPE with VALS. BTYPE must be the
+ // backend representation a of struct. VALS must be in the same order as the
+ // corresponding fields in BTYPE.
+ virtual Bexpression*
+ constructor_expression(Btype* btype, const std::vector<Bexpression*>& vals,
+ Location) = 0;
+
+ // Return an expression that constructs an array of BTYPE with INDEXES and
+ // VALS. INDEXES and VALS must have the same amount of elements. Each index
+ // in INDEXES must be in the same order as the corresponding value in VALS.
+ virtual Bexpression*
+ array_constructor_expression(Btype* btype,
+ const std::vector<unsigned long>& indexes,
+ const std::vector<Bexpression*>& vals,
+ Location) = 0;
+
+ // Return an expression for the address of BASE[INDEX].
+ // BASE has a pointer type. This is used for slice indexing.
+ virtual Bexpression*
+ pointer_offset_expression(Bexpression* base, Bexpression* index,
+ Location) = 0;
+
+ // Return an expression for ARRAY[INDEX] as an l-value. ARRAY is a valid
+ // fixed-length array, not a slice.
+ virtual Bexpression*
+ array_index_expression(Bexpression* array, Bexpression* index, Location) = 0;
+
+ // Create an expression for a call to FN with ARGS.
+ virtual Bexpression*
+ call_expression(Bexpression* fn, const std::vector<Bexpression*>& args,
+ Location) = 0;
+
// Statements.
// Create an error statement. This is used for cases which should
@@ -367,6 +415,15 @@ class Backend
virtual Bstatement*
statement_list(const std::vector<Bstatement*>&) = 0;
+ // Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if
+ // an exception occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and
+ // if not NULL, it will always be executed. This is used for handling defers
+ // in Go functions. In C++, the resulting code is of this form:
+ // try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; }
+ virtual Bstatement*
+ exception_handler_statement(Bstatement* bstat, Bstatement* except_stmt,
+ Bstatement* finally_stmt, Location) = 0;
+
// Blocks.
// Create a block. The frontend will call this function when it
@@ -570,6 +627,26 @@ class Backend
function(Btype* fntype, const std::string& name, const std::string& asm_name,
bool is_visible, bool is_declaration, bool is_inlinable,
bool disable_split_stack, bool in_unique_section, Location) = 0;
+
+ // Create a statement that runs all deferred calls for FUNCTION. This should
+ // be a statement that looks like this in C++:
+ // finish:
+ // try { UNDEFER; } catch { CHECK_DEFER; goto finish; }
+ virtual Bstatement*
+ function_defer_statement(Bfunction* function, Bexpression* undefer,
+ Bexpression* check_defer, Location) = 0;
+
+ // Record PARAM_VARS as the variables to use for the parameters of FUNCTION.
+ // This will only be called for a function definition. Returns true on
+ // success, false on failure.
+ virtual bool
+ function_set_parameters(Bfunction* function,
+ const std::vector<Bvariable*>& param_vars) = 0;
+
+ // Set the function body for FUNCTION using the code in CODE_STMT. Returns
+ // true on success, false on failure.
+ virtual bool
+ function_set_body(Bfunction* function, Bstatement* code_stmt) = 0;
};
// The backend interface has to define this function.
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index f45b4a22709..bd2e3183bfe 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -140,128 +140,81 @@ Expression::determine_type_no_context()
this->do_determine_type(&context);
}
-// Return a tree handling any conversions which must be done during
+// Return an expression 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)
+Expression*
+Expression::convert_for_assignment(Gogo* gogo, Type* lhs_type,
+ Expression* rhs, 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;
+ Type* rhs_type = rhs->type();
+ if (lhs_type->is_error()
+ || rhs_type->is_error()
+ || rhs->is_error_expression())
+ return Expression::make_error(location);
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);
+ return Expression::convert_type_to_interface(lhs_type, rhs, location);
else
- return Expression::convert_interface_to_interface(context, lhs_type,
- rhs_type, rhs_tree,
- false, location);
+ return Expression::convert_interface_to_interface(lhs_type, rhs, 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);
+ return Expression::convert_interface_to_type(lhs_type, rhs, 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;
+ // Assigning nil to a slice.
+ mpz_t zval;
+ mpz_init_set_ui(zval, 0UL);
+ Expression* zero = Expression::make_integer(&zval, NULL, location);
+ mpz_clear(zval);
+ Expression* nil = Expression::make_nil(location);
+ return Expression::make_slice_value(lhs_type, nil, zero, zero, location);
}
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))
+ return Expression::make_nil(location);
+ else if (Type::are_identical(lhs_type, rhs_type, false, NULL))
{
// 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))
+ return rhs;
+ }
+ else if (lhs_type->points_to() != NULL)
+ return Expression::make_unsafe_cast(lhs_type, rhs, location);
+ else if (lhs_type->is_numeric_type())
+ return Expression::make_cast(lhs_type, rhs, location);
+ else if ((lhs_type->struct_type() != NULL
+ && rhs_type->struct_type() != NULL)
+ || (lhs_type->array_type() != NULL
+ && rhs_type->array_type() != NULL))
{
// 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;
+ // TODO(cmang): This check is for a GCC-specific issue, and should be
+ // removed from the frontend. FIXME.
+ size_t lhs_size = gogo->backend()->type_size(lhs_type->get_backend(gogo));
+ size_t rhs_size = gogo->backend()->type_size(rhs_type->get_backend(gogo));
+ if (rhs_size == 0 || lhs_size == 0)
+ return rhs;
// 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);
+ return Expression::make_unsafe_cast(lhs_type, rhs, location);
}
else
- {
- go_assert(useless_type_conversion_p(lhs_type_tree, TREE_TYPE(rhs_tree)));
- return rhs_tree;
- }
+ return rhs;
}
-// Return a tree for a conversion from a non-interface type to an
+// Return an expression 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)
+Expression*
+Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs,
+ Location location)
{
- Gogo* gogo = context->gogo();
Interface_type* lhs_interface_type = lhs_type->interface_type();
bool lhs_is_empty = lhs_interface_type->is_empty();
@@ -270,29 +223,22 @@ Expression::convert_type_to_interface(Translate_context* context,
// When setting an interface to nil, we just set both fields to
// NULL.
+ Type* rhs_type = rhs->type();
if (rhs_type->is_nil_type())
{
- Btype* lhs_btype = lhs_type->get_backend(gogo);
- return expr_to_tree(gogo->backend()->zero_expression(lhs_btype));
+ Expression* nil = Expression::make_nil(location);
+ return Expression::make_interface_value(lhs_type, nil, nil, location);
}
// 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;
+ Expression* first_field;
if (lhs_is_empty)
- {
- Bexpression* rhs_bexpr =
- rhs_type->type_descriptor_pointer(gogo, location);
- first_field_value = expr_to_tree(rhs_bexpr);
- }
+ first_field = Expression::make_type_descriptor(rhs_type, location);
else
{
// Build the interface method table for this interface and this
@@ -307,131 +253,72 @@ Expression::convert_type_to_interface(Translate_context* context,
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);
+ first_field =
+ rhs_named_type->interface_method_table(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);
+ first_field =
+ rhs_struct_type->interface_method_table(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);
+ first_field = Expression::make_nil(location);
}
- 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;
+ Expression* obj;
if (rhs_type->points_to() != NULL)
{
- // We are assigning a pointer to the interface; the interface
+ // 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);
+ obj = rhs;
+ }
+ else
+ {
+ // We are assigning a non-pointer value to the interface; the
+ // interface gets a copy of the value in the heap.
+ obj = Expression::make_heap_expression(rhs, location);
}
- // We are assigning a non-pointer value to the interface; the
- // interface gets a copy of the value in the heap.
+ return Expression::make_interface_value(lhs_type, first_field, obj, location);
+}
- tree object_size = TYPE_SIZE_UNIT(TREE_TYPE(rhs_tree));
+// Return an expression for the type descriptor of RHS.
- 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);
+Expression*
+Expression::get_interface_type_descriptor(Expression* rhs)
+{
+ go_assert(rhs->type()->interface_type() != NULL);
+ Location location = rhs->location();
- 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);
+ // The type descriptor is the first field of an empty interface.
+ if (rhs->type()->interface_type()->is_empty())
+ return Expression::make_interface_info(rhs, INTERFACE_INFO_TYPE_DESCRIPTOR,
+ location);
- elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
- space);
+ Expression* mtable =
+ Expression::make_interface_info(rhs, INTERFACE_INFO_METHODS, location);
- return build2(COMPOUND_EXPR, lhs_type_tree, set,
- build_constructor(lhs_type_tree, init));
-}
+ Expression* descriptor =
+ Expression::make_unary(OPERATOR_MULT, mtable, location);
+ descriptor = Expression::make_field_reference(descriptor, 0, location);
+ Expression* nil = Expression::make_nil(location);
-// 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.
+ Expression* eq =
+ Expression::make_binary(OPERATOR_EQEQ, mtable, nil, location);
+ return Expression::make_conditional(eq, nil, descriptor, location);
+}
-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
+// Return an expression 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)
+Expression*
+Expression::convert_interface_to_interface(Type *lhs_type, Expression* rhs,
+ 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.
@@ -442,169 +329,75 @@ Expression::convert_interface_to_interface(Translate_context* context,
// Get the type descriptor for the right hand side. This will be
// NULL for a nil interface.
+ Expression* rhs_type_expr = Expression::get_interface_type_descriptor(rhs);
+ Expression* lhs_type_expr =
+ Expression::make_type_descriptor(lhs_type, 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);
-
- // 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;
-
+ Expression* first_field;
if (for_type_guard)
{
// A type assertion fails when converting a nil interface.
- Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo,
- location);
- tree lhs_type_descriptor = expr_to_tree(lhs_type_expr);
- 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);
+ first_field =
+ Runtime::make_call(Runtime::ASSERT_INTERFACE, location, 2,
+ lhs_type_expr, rhs_type_expr);
}
else if (lhs_is_empty)
{
- // A convertion to an empty interface always succeeds, and the
+ // A conversion 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);
+ first_field = rhs_type_expr;
}
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);
- Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo,
- location);
- tree lhs_type_descriptor = expr_to_tree(lhs_type_expr);
-
- 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);
+ first_field =
+ Runtime::make_call(Runtime::CONVERT_INTERFACE, location, 2,
+ lhs_type_expr, rhs_type_expr);
}
// 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);
+ Expression* obj =
+ Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT, location);
+ return Expression::make_interface_value(lhs_type, first_field, obj, location);
}
-// Return a tree for the conversion of an interface type to a
+// Return an expression 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)
+Expression*
+Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs,
+ 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.
- Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo,
- location);
- tree lhs_type_descriptor = expr_to_tree(lhs_type_expr);
-
- 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);
-
- Bexpression* rhs_inter_expr = rhs_type->type_descriptor_pointer(gogo,
- location);
- tree rhs_inter_descriptor = expr_to_tree(rhs_inter_expr);
-
- 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;
+ Expression* lhs_type_expr = Expression::make_type_descriptor(lhs_type,
+ location);
+ Expression* rhs_descriptor =
+ Expression::get_interface_type_descriptor(rhs);
+
+ Type* rhs_type = rhs->type();
+ Expression* rhs_inter_expr = Expression::make_type_descriptor(rhs_type,
+ location);
+
+ Expression* check_iface = Runtime::make_call(Runtime::CHECK_INTERFACE_TYPE,
+ location, 3, lhs_type_expr,
+ rhs_descriptor, rhs_inter_expr);
// 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);
+ Expression* obj = Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT,
+ location);
// 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);
+ obj = Expression::make_unsafe_cast(Type::make_pointer_type(lhs_type), obj,
+ location);
+ obj = Expression::make_unary(OPERATOR_MULT, obj, location);
}
-
- return build2(COMPOUND_EXPR, lhs_type_tree, call,
- fold_convert_loc(location.gcc_location(), lhs_type_tree, val));
+ return Expression::make_compound(check_iface, obj, location);
}
// Convert an expression to a tree. This is implemented by the child
@@ -674,54 +467,71 @@ Expression::backend_numeric_constant_expression(Translate_context* context,
return ret;
}
-// 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.
+// Return an expression which evaluates to true if VAL, of arbitrary integer
+// type, is negative or is more than the maximum value of the Go type "int".
-tree
-Expression::check_bounds(tree val, tree bound_type, tree sofar,
- Location loc)
+Expression*
+Expression::check_bounds(Expression* val, Location loc)
{
- tree val_type = TREE_TYPE(val);
- tree ret = NULL_TREE;
+ Type* val_type = val->type();
+ Type* bound_type = Type::lookup_integer_type("int");
+
+ int val_type_size;
+ bool val_is_unsigned = false;
+ if (val_type->integer_type() != NULL)
+ {
+ val_type_size = val_type->integer_type()->bits();
+ val_is_unsigned = val_type->integer_type()->is_unsigned();
+ }
+ else
+ {
+ if (!val_type->is_numeric_type()
+ || !Type::are_convertible(bound_type, val_type, NULL))
+ {
+ go_assert(saw_errors());
+ return Expression::make_boolean(true, loc);
+ }
+
+ if (val_type->complex_type() != NULL)
+ val_type_size = val_type->complex_type()->bits();
+ else
+ val_type_size = val_type->float_type()->bits();
+ }
- if (!TYPE_UNSIGNED(val_type))
+ Expression* negative_index = Expression::make_boolean(false, loc);
+ Expression* index_overflows = Expression::make_boolean(false, loc);
+ if (!val_is_unsigned)
{
- 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;
+ mpz_t zval;
+ mpz_init_set_ui(zval, 0UL);
+ Expression* zero = Expression::make_integer(&zval, val_type, loc);
+ mpz_clear(zval);
+
+ negative_index = Expression::make_binary(OPERATOR_LT, val, zero, loc);
}
- 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);
+ int bound_type_size = bound_type->integer_type()->bits();
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);
+ && val_is_unsigned))
+ {
+ mpz_t one;
+ mpz_init_set_ui(one, 1UL);
+
+ // maxval = 2^(bound_type_size - 1) - 1
+ mpz_t maxval;
+ mpz_init(maxval);
+ mpz_mul_2exp(maxval, one, bound_type_size - 1);
+ mpz_sub_ui(maxval, maxval, 1);
+ Expression* max = Expression::make_integer(&maxval, val_type, loc);
+ mpz_clear(one);
+ mpz_clear(maxval);
+
+ index_overflows = Expression::make_binary(OPERATOR_GT, val, max, loc);
}
- 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);
+ return Expression::make_binary(OPERATOR_OROR, negative_index, index_overflows,
+ loc);
}
void
@@ -1719,7 +1529,23 @@ String_expression::do_determine_type(const Type_context* context)
tree
String_expression::do_get_tree(Translate_context* context)
{
- return context->gogo()->go_string_constant_tree(this->val_);
+ Gogo* gogo = context->gogo();
+ Btype* btype = Type::make_string_type()->get_backend(gogo);
+
+ Location loc = this->location();
+ std::vector<Bexpression*> init(2);
+ Bexpression* str_cst =
+ gogo->backend()->string_constant_expression(this->val_);
+ init[0] = gogo->backend()->address_expression(str_cst, loc);
+
+ Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
+ mpz_t lenval;
+ mpz_init_set_ui(lenval, this->val_.length());
+ init[1] = gogo->backend()->integer_constant_expression(int_btype, lenval);
+ mpz_clear(lenval);
+
+ Bexpression* ret = gogo->backend()->constructor_expression(btype, init, loc);
+ return expr_to_tree(ret);
}
// Write string literal to string dump.
@@ -1826,6 +1652,116 @@ Expression::make_string(const std::string& val, Location location)
return new String_expression(val, location);
}
+// An expression that evaluates to some characteristic of a string.
+// This is used when indexing, bound-checking, or nil checking a string.
+
+class String_info_expression : public Expression
+{
+ public:
+ String_info_expression(Expression* string, String_info string_info,
+ Location location)
+ : Expression(EXPRESSION_STRING_INFO, location),
+ string_(string), string_info_(string_info)
+ { }
+
+ protected:
+ Type*
+ do_type();
+
+ void
+ do_determine_type(const Type_context*)
+ { go_unreachable(); }
+
+ Expression*
+ do_copy()
+ {
+ return new String_info_expression(this->string_->copy(), this->string_info_,
+ this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ void
+ do_issue_nil_check()
+ { this->string_->issue_nil_check(); }
+
+ private:
+ // The string for which we are getting information.
+ Expression* string_;
+ // What information we want.
+ String_info string_info_;
+};
+
+// Return the type of the string info.
+
+Type*
+String_info_expression::do_type()
+{
+ switch (this->string_info_)
+ {
+ case STRING_INFO_DATA:
+ {
+ Type* byte_type = Type::lookup_integer_type("uint8");
+ return Type::make_pointer_type(byte_type);
+ }
+ case STRING_INFO_LENGTH:
+ return Type::lookup_integer_type("int");
+ default:
+ go_unreachable();
+ }
+}
+
+// Return string information in GENERIC.
+
+tree
+String_info_expression::do_get_tree(Translate_context* context)
+{
+ Gogo* gogo = context->gogo();
+
+ Bexpression* bstring = tree_to_expr(this->string_->get_tree(context));
+ Bexpression* ret;
+ switch (this->string_info_)
+ {
+ case STRING_INFO_DATA:
+ case STRING_INFO_LENGTH:
+ ret = gogo->backend()->struct_field_expression(bstring, this->string_info_,
+ this->location());
+ break;
+ default:
+ go_unreachable();
+ }
+ return expr_to_tree(ret);
+}
+
+// Dump ast representation for a type info expression.
+
+void
+String_info_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "stringinfo(";
+ this->string_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ",";
+ ast_dump_context->ostream() <<
+ (this->string_info_ == STRING_INFO_DATA ? "data"
+ : this->string_info_ == STRING_INFO_LENGTH ? "length"
+ : "unknown");
+ ast_dump_context->ostream() << ")";
+}
+
+// Make a string info expression.
+
+Expression*
+Expression::make_string_info(Expression* string, String_info string_info,
+ Location location)
+{
+ return new String_info_expression(string, string_info, location);
+}
+
// Make an integer expression.
class Integer_expression : public Expression
@@ -2826,16 +2762,8 @@ Const_expression::do_check_types(Gogo*)
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 (this->type_ != NULL && this->type_->is_error())
+ 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
@@ -2855,24 +2783,15 @@ Const_expression::do_get_tree(Translate_context* 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;
+ Gogo* gogo = context->gogo();
+ Bexpression* ret =
+ tree_to_expr(this->constant_->get_tree(gogo, context->function()));
+ if (this->type_ != NULL)
+ {
+ Btype* btype = this->type_->get_backend(gogo);
+ ret = gogo->backend()->convert_expression(btype, ret, this->location());
+ }
+ return expr_to_tree(ret);
}
// Dump ast representation for constant expression.
@@ -3221,8 +3140,10 @@ Expression*
Type_conversion_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
- if (this->type()->is_string_type()
- && this->expr_->type()->is_slice_type()
+ if (((this->type()->is_string_type()
+ && this->expr_->type()->is_slice_type())
+ || (this->type()->interface_type() != NULL
+ && this->expr_->type()->interface_type() != NULL))
&& !this->expr_->is_variable())
{
Temporary_statement* temp =
@@ -3325,73 +3246,50 @@ Type_conversion_expression::do_check_types(Gogo*)
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)
+
+ Gogo* gogo = context->gogo();
+ Btype* btype = type->get_backend(gogo);
+ Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context));
+ Location loc = this->location();
+
+ if (Type::are_identical(type, expr_type, false, NULL))
{
- if (expr_type->integer_type() != NULL
- || expr_type->float_type() != NULL)
- ret = fold(convert_to_real(type_tree, expr_tree));
- else
- go_unreachable();
+ Bexpression* bconvert =
+ gogo->backend()->convert_expression(btype, bexpr, loc);
+ return expr_to_tree(bconvert);
}
- else if (type->complex_type() != NULL)
+ else if (type->interface_type() != NULL
+ || expr_type->interface_type() != NULL)
{
- if (expr_type->complex_type() != NULL)
- ret = fold(convert_to_complex(type_tree, expr_tree));
- else
- go_unreachable();
+ Expression* conversion =
+ Expression::convert_for_assignment(gogo, type, this->expr_,
+ this->location());
+ return conversion->get_tree(context);
}
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 (tree_fits_shwi_p (expr_tree))
+ mpz_t intval;
+ Numeric_constant nc;
+ if (this->expr_->numeric_constant_value(&nc)
+ && nc.to_int(&intval)
+ && mpz_fits_ushort_p(intval))
{
- HOST_WIDE_INT intval = tree_to_shwi (expr_tree);
std::string s;
- Lex::append_char(intval, true, &s, this->location());
- Expression* se = Expression::make_string(s, this->location());
+ Lex::append_char(mpz_get_ui(intval), true, &s, loc);
+ mpz_clear(intval);
+ Expression* se = Expression::make_string(s, loc);
return se->get_tree(context);
}
Expression* i2s_expr =
- Runtime::make_call(Runtime::INT_TO_STRING, this->location(), 1,
- this->expr_);
- i2s_expr = Expression::make_cast(type, i2s_expr, this->location());
- ret = i2s_expr->get_tree(context);
+ Runtime::make_call(Runtime::INT_TO_STRING, loc, 1, this->expr_);
+ return Expression::make_cast(type, i2s_expr, loc)->get_tree(context);
}
else if (type->is_string_type() && expr_type->is_slice_type())
{
- Location location = this->location();
Array_type* a = expr_type->array_type();
Type* e = a->element_type()->forwarded();
go_assert(e->integer_type() != NULL);
@@ -3407,46 +3305,50 @@ Type_conversion_expression::do_get_tree(Translate_context* context)
}
Expression* valptr = a->get_value_pointer(gogo, this->expr_);
Expression* len = a->get_length(gogo, this->expr_);
- Expression* a2s_expr = Runtime::make_call(code, location, 2, valptr, len);
- ret = a2s_expr->get_tree(context);
+ return Runtime::make_call(code, loc, 2, valptr, len)->get_tree(context);
}
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);
- Expression* s2a_expr;
+ Runtime::Function code;
if (e->integer_type()->is_byte())
- s2a_expr = Runtime::make_call(Runtime::STRING_TO_BYTE_ARRAY,
- this->location(), 1, this->expr_);
+ code = Runtime::STRING_TO_BYTE_ARRAY;
else
{
go_assert(e->integer_type()->is_rune());
- s2a_expr = Runtime::make_call(Runtime::STRING_TO_INT_ARRAY,
- this->location(), 1, this->expr_);
+ code = Runtime::STRING_TO_INT_ARRAY;
}
- s2a_expr = Expression::make_unsafe_cast(type, s2a_expr,
- this->location());
- ret = s2a_expr->get_tree(context);
+ Expression* s2a = Runtime::make_call(code, loc, 1, this->expr_);
+ return Expression::make_unsafe_cast(type, s2a, loc)->get_tree(context);
+ }
+ else if (type->is_numeric_type())
+ {
+ go_assert(Type::are_convertible(type, expr_type, NULL));
+ Bexpression* bconvert =
+ gogo->backend()->convert_expression(btype, bexpr, loc);
+ return expr_to_tree(bconvert);
}
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);
+ && (expr_type->points_to() != NULL
+ || expr_type->integer_type()))
+ || (expr_type->is_unsafe_pointer_type()
+ && type->points_to() != NULL)
+ || (this->may_convert_function_types_
+ && type->function_type() != NULL
+ && expr_type->function_type() != NULL))
+ {
+ Bexpression* bconvert =
+ gogo->backend()->convert_expression(btype, bexpr, loc);
+ return expr_to_tree(bconvert);
+ }
else
- ret = Expression::convert_for_assignment(context, type, expr_type,
- expr_tree, this->location());
-
- return ret;
+ {
+ Expression* conversion =
+ Expression::convert_for_assignment(gogo, type, this->expr_, loc);
+ return conversion->get_tree(context);
+ }
}
// Output a type conversion in a constant expression.
@@ -3560,58 +3462,57 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
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())
+ if (t->array_type() != NULL)
+ go_assert(et->array_type() != NULL
+ && t->is_slice_type() == et->is_slice_type());
+ else if (t->struct_type() != NULL)
{
- go_assert(et->is_slice_type());
- use_view_convert = true;
+ if (t->named_type() != NULL
+ && et->named_type() != NULL
+ && !Type::are_convertible(t, et, NULL))
+ {
+ go_assert(saw_errors());
+ return error_mark_node;
+ }
+
+ go_assert(et->struct_type() != NULL
+ && Type::are_convertible(t, et, NULL));
}
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());
+ go_assert(et->points_to() != NULL
+ || et->channel_type() != NULL
+ || et->map_type() != NULL
+ || et->function_type() != 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())
+ else if (t->interface_type() != NULL)
{
+ bool empty_iface = t->interface_type()->is_empty();
go_assert(et->interface_type() != NULL
- && et->interface_type()->is_empty());
- use_view_convert = true;
+ && et->interface_type()->is_empty() == empty_iface);
}
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);
- }
+ 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);
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);
+ Gogo* gogo = context->gogo();
+ Btype* btype = t->get_backend(gogo);
+ Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context));
+ Location loc = this->location();
+ Bexpression* ret =
+ gogo->backend()->convert_expression(btype, bexpr, loc);
+ return expr_to_tree(ret);
}
// Dump ast representation for an unsafe type conversion expression.
@@ -3757,7 +3658,7 @@ class Unary_expression : public Expression
};
// If we are taking the address of a composite literal, and the
-// contents are not constant, then we want to make a heap composite
+// contents are not constant, then we want to make a heap expression
// instead.
Expression*
@@ -4758,9 +4659,19 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
{
case OPERATOR_PLUS:
mpz_add(val, left_val, right_val);
+ if (mpz_sizeinbase(val, 2) > 0x100000)
+ {
+ error_at(location, "constant addition overflow");
+ mpz_set_ui(val, 1);
+ }
break;
case OPERATOR_MINUS:
mpz_sub(val, left_val, right_val);
+ if (mpz_sizeinbase(val, 2) > 0x100000)
+ {
+ error_at(location, "constant subtraction overflow");
+ mpz_set_ui(val, 1);
+ }
break;
case OPERATOR_OR:
mpz_ior(val, left_val, right_val);
@@ -4770,6 +4681,11 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
break;
case OPERATOR_MULT:
mpz_mul(val, left_val, right_val);
+ if (mpz_sizeinbase(val, 2) > 0x100000)
+ {
+ error_at(location, "constant multiplication overflow");
+ mpz_set_ui(val, 1);
+ }
break;
case OPERATOR_DIV:
if (mpz_sgn(right_val) != 0)
@@ -4797,7 +4713,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
else
{
error_at(location, "shift count overflow");
- mpz_set_ui(val, 0);
+ mpz_set_ui(val, 1);
}
break;
}
@@ -4808,7 +4724,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
if (mpz_cmp_ui(right_val, shift) != 0)
{
error_at(location, "shift count overflow");
- mpz_set_ui(val, 0);
+ mpz_set_ui(val, 1);
}
else
{
@@ -6888,7 +6804,7 @@ Bound_method_expression::do_get_tree(Translate_context* context)
vals->push_back(val);
Expression* ret = Expression::make_struct_composite_literal(st, vals, loc);
- ret = Expression::make_heap_composite(ret, loc);
+ ret = Expression::make_heap_expression(ret, loc);
tree ret_tree = ret->get_tree(context);
@@ -7776,27 +7692,33 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
return false;
if (arg_type->is_abstract())
return false;
+ if (this->seen_)
+ return false;
unsigned int ret;
if (this->code_ == BUILTIN_SIZEOF)
{
- if (!arg_type->backend_type_size(this->gogo_, &ret))
+ this->seen_ = true;
+ bool ok = arg_type->backend_type_size(this->gogo_, &ret);
+ this->seen_ = false;
+ if (!ok)
return false;
}
else if (this->code_ == BUILTIN_ALIGNOF)
{
+ bool ok;
+ this->seen_ = true;
if (arg->field_reference_expression() == NULL)
- {
- if (!arg_type->backend_type_align(this->gogo_, &ret))
- return false;
- }
+ ok = arg_type->backend_type_align(this->gogo_, &ret);
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;
+ ok = arg_type->backend_type_field_align(this->gogo_, &ret);
}
+ this->seen_ = false;
+ if (!ok)
+ return false;
}
else
go_unreachable();
@@ -7813,6 +7735,9 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
Field_reference_expression* farg = arg->field_reference_expression();
if (farg == NULL)
return false;
+ if (this->seen_)
+ return false;
+
unsigned int total_offset = 0;
while (true)
{
@@ -7823,10 +7748,13 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
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;
+ this->seen_ = true;
+ bool ok = st->struct_type()->backend_field_offset(this->gogo_,
+ farg->field_index(),
+ &offset);
+ this->seen_ = false;
+ if (!ok)
+ return false;
total_offset += offset;
if (farg->implicit() && struct_expr->field_reference_expression() != NULL)
{
@@ -8439,7 +8367,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
{
const Expression_list* args = this->args();
go_assert(args != NULL && args->size() == 1);
- Expression* arg = *args->begin();
+ Expression* arg = args->front();
Type* arg_type = arg->type();
if (this->seen_)
@@ -8448,31 +8376,22 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
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);
+ arg = Expression::make_unary(OPERATOR_MULT, arg, location);
}
Type* int_type = Type::lookup_integer_type("int");
- tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
-
- tree val_tree;
+ Expression* val;
if (this->code_ == BUILTIN_LEN)
{
if (arg_type->is_string_type())
- val_tree = String_type::length_tree(gogo, arg_tree);
+ val = Expression::make_string_info(arg, STRING_INFO_LENGTH,
+ location);
else if (arg_type->array_type() != NULL)
{
if (this->seen_)
@@ -8481,34 +8400,13 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
this->seen_ = true;
- Expression* len = arg_type->array_type()->get_length(gogo, arg);
- val_tree = len->get_tree(context);
+ val = arg_type->array_type()->get_length(gogo, arg);
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);
- }
+ val = Runtime::make_call(Runtime::MAP_LEN, location, 1, arg);
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);
- }
+ val = Runtime::make_call(Runtime::CHAN_LEN, location, 1, arg);
else
go_unreachable();
}
@@ -8522,36 +8420,24 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
this->seen_ = true;
- Expression* cap =
- arg_type->array_type()->get_capacity(gogo, arg);
- val_tree = cap->get_tree(context);
+ val = arg_type->array_type()->get_capacity(gogo, arg);
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);
- }
+ val = Runtime::make_call(Runtime::CHAN_CAP, location, 1, arg);
else
go_unreachable();
}
- return fold_convert_loc(location.gcc_location(), int_type_tree,
- val_tree);
+ return Expression::make_cast(int_type, val,
+ location)->get_tree(context);
}
case BUILTIN_PRINT:
case BUILTIN_PRINTLN:
{
const bool is_ln = this->code_ == BUILTIN_PRINTLN;
- tree stmt_list = NULL_TREE;
+ Expression* print_stmts = NULL;
const Expression_list* call_args = this->args();
if (call_args != NULL)
@@ -8562,139 +8448,91 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
{
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();
+ Expression* print_space =
+ Runtime::make_call(Runtime::PRINT_SPACE,
+ this->location(), 0);
- tree arg = (*p)->get_tree(context);
- if (arg == error_mark_node)
- return error_mark_node;
+ print_stmts =
+ Expression::make_compound(print_stmts, print_space,
+ location);
+ }
- tree* pfndecl;
- const char* fnname;
+ Expression* arg = *p;
+ Type* type = arg->type();
+ Runtime::Function code;
if (type->is_string_type())
- {
- static tree print_string_fndecl;
- pfndecl = &print_string_fndecl;
- fnname = "__go_print_string";
- }
+ code = Runtime::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);
+ arg = Expression::make_cast(itype, arg, location);
+ code = Runtime::PRINT_UINT64;
}
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);
+ arg = Expression::make_cast(itype, arg, location);
+ code = Runtime::PRINT_INT64;
}
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);
+ Type* dtype = Type::lookup_float_type("float64");
+ arg = Expression::make_cast(dtype, arg, location);
+ code = Runtime::PRINT_DOUBLE;
}
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);
+ Type* ctype = Type::lookup_complex_type("complex128");
+ arg = Expression::make_cast(ctype, arg, location);
+ code = Runtime::PRINT_COMPLEX;
}
else if (type->is_boolean_type())
- {
- static tree print_bool_fndecl;
- pfndecl = &print_bool_fndecl;
- fnname = "__go_print_bool";
- }
+ code = Runtime::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);
+ arg = Expression::make_cast(type, arg, location);
+ code = Runtime::PRINT_POINTER;
}
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";
- }
+ code = Runtime::PRINT_EMPTY_INTERFACE;
else
- {
- static tree print_interface_fndecl;
- pfndecl = &print_interface_fndecl;
- fnname = "__go_print_interface";
- }
+ code = Runtime::PRINT_INTERFACE;
}
else if (type->is_slice_type())
- {
- static tree print_slice_fndecl;
- pfndecl = &print_slice_fndecl;
- fnname = "__go_print_slice";
- }
+ code = Runtime::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);
+ Expression* call = Runtime::make_call(code, location, 1, arg);
+ if (print_stmts == NULL)
+ print_stmts = call;
+ else
+ print_stmts = Expression::make_compound(print_stmts, call,
+ location);
}
}
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);
+ Expression* print_nl =
+ Runtime::make_call(Runtime::PRINT_NL, location, 0);
+ if (print_stmts == NULL)
+ print_stmts = print_nl;
+ else
+ print_stmts = Expression::make_compound(print_stmts, print_nl,
+ location);
}
- return stmt_list;
+ return print_stmts->get_tree(context);
}
case BUILTIN_PANIC:
@@ -8702,29 +8540,13 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
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;
+ arg = Expression::convert_for_assignment(gogo, empty, arg, location);
+
+ Expression* panic =
+ Runtime::make_call(Runtime::PANIC, location, 1, arg);
+ return panic->get_tree(context);
}
case BUILTIN_RECOVER:
@@ -8734,49 +8556,22 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
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);
+ nil = Expression::convert_for_assignment(gogo, empty, nil, 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);
+ Expression* recover = Runtime::make_call((this->is_deferred()
+ ? Runtime::DEFERRED_RECOVER
+ : Runtime::RECOVER),
+ location, 0);
+ Expression* cond =
+ Expression::make_conditional(arg, recover, nil, location);
+ return cond->get_tree(context);
}
case BUILTIN_CLOSE:
@@ -8784,17 +8579,9 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
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);
+ Expression* close = Runtime::make_call(Runtime::CLOSE, location,
+ 1, arg);
+ return close->get_tree(context);
}
case BUILTIN_SIZEOF:
@@ -8810,8 +8597,12 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
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);
+ mpz_t ival;
+ nc.get_int(&ival);
+ Expression* int_cst =
+ Expression::make_integer(&ival, uintptr_type, location);
+ mpz_clear(ival);
+ return int_cst->get_tree(context);
}
case BUILTIN_COPY:
@@ -8821,88 +8612,51 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
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();
go_assert(arg1->is_variable());
- Expression* arg1_valptr = at->get_value_pointer(gogo, arg1);
- Expression* arg1_len_expr = at->get_length(gogo, arg1);
- tree arg1_val = arg1_valptr->get_tree(context);
- tree arg1_len = arg1_len_expr->get_tree(context);
- if (arg1_val == error_mark_node || arg1_len == error_mark_node)
- return error_mark_node;
+ Expression* arg1_val = at->get_value_pointer(gogo, arg1);
+ Expression* arg1_len = at->get_length(gogo, arg1);
Type* arg2_type = arg2->type();
- tree arg2_val;
- tree arg2_len;
+ go_assert(arg2->is_variable());
+ Expression* arg2_val;
+ Expression* arg2_len;
if (arg2_type->is_slice_type())
{
at = arg2_type->array_type();
- go_assert(arg2->is_variable());
- Expression* arg2_valptr = at->get_value_pointer(gogo, arg2);
- Expression* arg2_len_expr = at->get_length(gogo, arg2);
- arg2_val = arg2_valptr->get_tree(context);
- arg2_len = arg2_len_expr->get_tree(context);
+ arg2_val = at->get_value_pointer(gogo, arg2);
+ arg2_len = at->get_length(gogo, arg2);
}
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);
+ go_assert(arg2->is_variable());
+ arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
+ location);
+ arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
+ location);
}
- 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);
+ Expression* cond =
+ Expression::make_binary(OPERATOR_LT, arg1_len, arg2_len, location);
+ Expression* length =
+ Expression::make_conditional(cond, arg1_len, arg2_len, location);
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);
+ mpz_t size;
+ size_t element_size = gogo->backend()->type_size(element_btype);
+ mpz_init_set_ui(size, element_size);
+ Expression* size_expr = Expression::make_integer(&size, length->type(), location);
+ mpz_clear(size);
+
+ Expression* bytecount =
+ Expression::make_binary(OPERATOR_MULT, size_expr, length, location);
+ Expression* copy = Runtime::make_call(Runtime::COPY, location, 3,
+ arg1_val, arg2_val, bytecount);
+
+ Expression* compound = Expression::make_compound(copy, length, location);
+ return compound->get_tree(context);
}
case BUILTIN_APPEND:
@@ -8912,67 +8666,40 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
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;
+ go_assert(arg2->is_variable());
+ Expression* arg2_val;
+ Expression* arg2_len;
+ mpz_t 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);
+ arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
+ location);
+ arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
+ location);
+ mpz_init_set_ui(size, 1UL);
}
else
{
- go_assert(arg2->is_variable());
- arg2_val =
- at->get_value_pointer(gogo, arg2)->get_tree(context);
- arg2_len = at->get_length(gogo, arg2)->get_tree(context);
+ arg2_val = at->get_value_pointer(gogo, arg2);
+ arg2_len = at->get_length(gogo, arg2);
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);
+ size_t element_size = gogo->backend()->type_size(element_btype);
+ mpz_init_set_ui(size, element_size);
}
-
- 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);
+ Expression* element_size =
+ Expression::make_integer(&size, NULL, location);
+ mpz_clear(size);
+
+ Expression* append = Runtime::make_call(Runtime::APPEND, location, 4,
+ arg1, arg2_val, arg2_len,
+ element_size);
+ append = Expression::make_unsafe_cast(arg1->type(), append, location);
+ return append->get_tree(context);
}
case BUILTIN_REAL:
@@ -8981,34 +8708,25 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
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);
+
+ Bexpression* ret;
+ Bexpression* bcomplex = tree_to_expr(arg->get_tree(context));
+ if (this->code_ == BUILTIN_REAL)
+ ret = gogo->backend()->real_part_expression(bcomplex, location);
+ else
+ ret = gogo->backend()->imag_part_expression(bcomplex, location);
+ return expr_to_tree(ret);
}
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);
+ Bexpression* breal = tree_to_expr(args->front()->get_tree(context));
+ Bexpression* bimag = tree_to_expr(args->back()->get_tree(context));
+ Bexpression* ret =
+ gogo->backend()->complex_expression(breal, bimag, location);
+ return expr_to_tree(ret);
}
default:
@@ -9382,6 +9100,37 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
this->varargs_are_lowered_ = true;
}
+// Flatten a call with multiple results into a temporary.
+
+Expression*
+Call_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter)
+{
+ size_t rc = this->result_count();
+ if (rc > 1 && this->call_temp_ == NULL)
+ {
+ Struct_field_list* sfl = new Struct_field_list();
+ Function_type* fntype = this->get_function_type();
+ const Typed_identifier_list* results = fntype->results();
+ Location loc = this->location();
+
+ int i = 0;
+ char buf[10];
+ for (Typed_identifier_list::const_iterator p = results->begin();
+ p != results->end();
+ ++p, ++i)
+ {
+ snprintf(buf, sizeof buf, "res%d", i);
+ sfl->push_back(Struct_field(Typed_identifier(buf, p->type(), loc)));
+ }
+
+ Struct_type* st = Type::make_struct_type(sfl, loc);
+ this->call_temp_ = Statement::make_temporary(st, NULL, loc);
+ inserter->insert(this->call_temp_);
+ }
+
+ return this;
+}
+
// Get the function type. This can return NULL in error cases.
Function_type*
@@ -9703,8 +9452,8 @@ Call_expression::interface_method_function(
tree
Call_expression::do_get_tree(Translate_context* context)
{
- if (this->tree_ != NULL_TREE)
- return this->tree_;
+ if (this->call_ != NULL)
+ return expr_to_tree(this->call_);
Function_type* fntype = this->get_function_type();
if (fntype == NULL)
@@ -9733,11 +9482,12 @@ Call_expression::do_get_tree(Translate_context* context)
has_closure_arg = true;
int nargs;
- tree* args;
+ std::vector<Bexpression*> fn_args;
if (this->args_ == NULL || this->args_->empty())
{
nargs = is_interface_method ? 1 : 0;
- args = nargs == 0 ? NULL : new tree[nargs];
+ if (nargs > 0)
+ fn_args.resize(1);
}
else if (fntype->parameters() == NULL || fntype->parameters()->empty())
{
@@ -9746,8 +9496,8 @@ Call_expression::do_get_tree(Translate_context* context)
&& fntype->is_method()
&& this->args_->size() == 1);
nargs = 1;
- args = new tree[nargs];
- args[0] = this->args_->front()->get_tree(context);
+ fn_args.resize(1);
+ fn_args[0] = tree_to_expr(this->args_->front()->get_tree(context));
}
else
{
@@ -9756,239 +9506,138 @@ Call_expression::do_get_tree(Translate_context* context)
nargs = this->args_->size();
int i = is_interface_method ? 1 : 0;
nargs += i;
- args = new tree[nargs];
+ fn_args.resize(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);
+ fn_args[i] = tree_to_expr((*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)
- return error_mark_node;
+ Expression* arg =
+ Expression::convert_for_assignment(gogo, pp->type(), *pe,
+ location);
+ fn_args[i] = tree_to_expr(arg->get_tree(context));
}
go_assert(pp == params->end());
go_assert(i == nargs);
}
- tree fntype_tree = type_to_tree(fntype->get_backend(gogo));
- tree fnfield_type = type_to_tree(fntype->get_backend_fntype(gogo));
- if (fntype_tree == error_mark_node || fnfield_type == error_mark_node)
- return error_mark_node;
- go_assert(FUNCTION_POINTER_TYPE_P(fnfield_type));
- tree rettype = TREE_TYPE(TREE_TYPE(fnfield_type));
- if (rettype == error_mark_node)
- return error_mark_node;
-
- tree fn;
- tree closure_tree;
+ Expression* fn;
+ Expression* closure = NULL;
if (func != NULL)
{
Named_object* no = func->named_object();
- fn = expr_to_tree(Func_expression::get_code_pointer(gogo, no, location));
- if (!has_closure)
- closure_tree = NULL_TREE;
- else
- {
- closure_tree = func->closure()->get_tree(context);
- if (closure_tree == error_mark_node)
- return error_mark_node;
- }
+ fn = Expression::make_func_code_reference(no, location);
+ if (has_closure)
+ closure = func->closure();
}
else if (!is_interface_method)
{
- closure_tree = this->fn_->get_tree(context);
- if (closure_tree == error_mark_node)
- return error_mark_node;
- tree fnc = fold_convert_loc(location.gcc_location(), fntype_tree,
- closure_tree);
- go_assert(POINTER_TYPE_P(TREE_TYPE(fnc))
- && (TREE_CODE(TREE_TYPE(TREE_TYPE(fnc)))
- == RECORD_TYPE));
- tree field = TYPE_FIELDS(TREE_TYPE(TREE_TYPE(fnc)));
- fn = fold_build3_loc(location.gcc_location(), COMPONENT_REF,
- TREE_TYPE(field),
- build_fold_indirect_ref_loc(location.gcc_location(),
- fnc),
- field, NULL_TREE);
- }
+ closure = this->fn_;
+
+ // The backend representation of this function type is a pointer
+ // to a struct whose first field is the actual function to call.
+ Type* pfntype =
+ Type::make_pointer_type(
+ Type::make_pointer_type(Type::make_void_type()));
+ fn = Expression::make_unsafe_cast(pfntype, this->fn_, location);
+ fn = Expression::make_unary(OPERATOR_MULT, fn, location);
+ }
else
{
Expression* first_arg;
- Expression* fn_expr =
- this->interface_method_function(interface_method, &first_arg);
- args[0] = first_arg->get_tree(context);
- fn = fn_expr->get_tree(context);
-
- if (fn == error_mark_node)
- return error_mark_node;
- closure_tree = NULL_TREE;
- }
-
- if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
- 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. We don't do this for an interface
- // method because 1) an interface method never refers to itself, so
- // we always have a function type here; 2) we pass an extra first
- // argument to an interface method, so fnfield_type is not correct.
- if ((!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl)) && !is_interface_method)
- fn = fold_convert_loc(location.gcc_location(), fnfield_type, 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]);
- }
- }
- }
+ fn = this->interface_method_function(interface_method, &first_arg);
+ fn_args[0] = tree_to_expr(first_arg->get_tree(context));
}
- if (func == NULL)
- fn = save_expr(fn);
-
if (!has_closure_arg)
- go_assert(closure_tree == NULL_TREE);
+ go_assert(closure == NULL);
else
{
// Pass the closure argument by calling the function function
// __go_set_closure. In the order_evaluations pass we have
// ensured that if any parameters contain call expressions, they
// will have been moved out to temporary variables.
-
- go_assert(closure_tree != NULL_TREE);
- closure_tree = fold_convert_loc(location.gcc_location(), ptr_type_node,
- closure_tree);
- static tree set_closure_fndecl;
- tree set_closure = Gogo::call_builtin(&set_closure_fndecl,
- location,
- "__go_set_closure",
- 1,
- void_type_node,
- ptr_type_node,
- closure_tree);
- if (set_closure == error_mark_node)
- return error_mark_node;
- fn = build2_loc(location.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(fn), set_closure, fn);
+ go_assert(closure != NULL);
+ Expression* set_closure =
+ Runtime::make_call(Runtime::SET_CLOSURE, location, 1, closure);
+ fn = Expression::make_compound(set_closure, fn, location);
}
- tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype,
- fn, nargs, args);
- delete[] args;
-
- SET_EXPR_LOCATION(ret, location.gcc_location());
+ Btype* bft = fntype->get_backend_fntype(gogo);
+ Bexpression* bfn = tree_to_expr(fn->get_tree(context));
+ bfn = gogo->backend()->convert_expression(bft, bfn, location);
+ Bexpression* call = gogo->backend()->call_expression(bfn, fn_args, location);
- // 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)
+ if (this->results_ != NULL)
{
- tree t = type_to_tree(this->type()->base()->get_backend(gogo));
- ret = fold_convert_loc(location.gcc_location(), t, ret);
- }
+ go_assert(this->call_temp_ != NULL);
+ Expression* call_ref =
+ Expression::make_temporary_reference(this->call_temp_, location);
+ Bexpression* bcall_ref = tree_to_expr(call_ref->get_tree(context));
+ Bstatement* assn_stmt =
+ gogo->backend()->assignment_statement(bcall_ref, call, location);
- 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);
- }
+ this->call_ = this->set_results(context, bcall_ref);
- if (this->results_ != NULL)
- ret = this->set_results(context, ret);
-
- this->tree_ = ret;
+ Bexpression* set_and_call =
+ gogo->backend()->compound_expression(assn_stmt, this->call_,
+ location);
+ return expr_to_tree(set_and_call);
+ }
- return ret;
+ this->call_ = call;
+ return expr_to_tree(this->call_);
}
// Set the result variables if this call returns multiple results.
-tree
-Call_expression::set_results(Translate_context* context, tree call_tree)
+Bexpression*
+Call_expression::set_results(Translate_context* context, Bexpression* call)
{
- 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;
- }
+ Gogo* gogo = context->gogo();
+ Bexpression* results = NULL;
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))
+ for (size_t i = 0; i < rc; ++i)
{
- go_assert(field != NULL_TREE);
-
Temporary_statement* temp = this->result(i);
if (temp == NULL)
{
go_assert(saw_errors());
- return error_mark_node;
+ return gogo->backend()->error_expression();
}
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);
+ Bexpression* result_ref = tree_to_expr(ref->get_tree(context));
+ Bexpression* call_result =
+ gogo->backend()->struct_field_expression(call, i, loc);
+ Bstatement* assn_stmt =
+ gogo->backend()->assignment_statement(result_ref, call_result, loc);
- append_to_statement_list(set_tree, &stmt_list);
- }
- go_assert(field == NULL_TREE);
+ Bexpression* result =
+ gogo->backend()->compound_expression(assn_stmt, call_result, loc);
- return save_expr(stmt_list);
+ if (results == NULL)
+ results = result;
+ else
+ {
+ Bstatement* expr_stmt = gogo->backend()->expression_statement(result);
+ results =
+ gogo->backend()->compound_expression(expr_stmt, results, loc);
+ }
+ }
+ return results;
}
// Dump ast representation for a call expressin.
@@ -10333,6 +9982,9 @@ class Array_index_expression : public Expression
int
do_traverse(Traverse*);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
Type*
do_type();
@@ -10343,9 +9995,6 @@ class Array_index_expression : public Expression
do_check_types(Gogo*);
Expression*
- do_flatten(Gogo*, Named_object*, Statement_inserter*);
-
- Expression*
do_copy()
{
return Expression::make_array_index(this->array_->copy(),
@@ -10586,19 +10235,41 @@ Array_index_expression::do_check_types(Gogo*)
}
}
-// Flatten array indexing by using a temporary variable for slices.
+// Flatten array indexing by using temporary variables for slices and indexes.
Expression*
Array_index_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
Location loc = this->location();
+ Temporary_statement* temp;
if (this->array_->type()->is_slice_type() && !this->array_->is_variable())
{
- Temporary_statement* temp = Statement::make_temporary(NULL, this->array_, loc);
+ temp = Statement::make_temporary(NULL, this->array_, loc);
inserter->insert(temp);
this->array_ = Expression::make_temporary_reference(temp, loc);
}
+ if (!this->start_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->start_, loc);
+ inserter->insert(temp);
+ this->start_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (this->end_ != NULL
+ && !this->end_->is_nil_expression()
+ && !this->end_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->end_, loc);
+ inserter->insert(temp);
+ this->end_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (this->cap_ != NULL && !this->cap_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->cap_, loc);
+ inserter->insert(temp);
+ this->cap_ = Expression::make_temporary_reference(temp, loc);
+ }
+
return this;
}
@@ -10625,9 +10296,6 @@ Array_index_expression::do_is_addressable() const
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)
{
@@ -10636,66 +10304,40 @@ Array_index_expression::do_get_tree(Translate_context* context)
}
go_assert(!array_type->is_slice_type() || this->array_->is_variable());
- tree type_tree = type_to_tree(array_type->get_backend(gogo));
- if (type_tree == error_mark_node)
- return error_mark_node;
+ Location loc = this->location();
+ Gogo* gogo = context->gogo();
+
+ Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
- tree length_tree = NULL_TREE;
+ // We need to convert the length and capacity to the Go "int" type here
+ // because the length of a fixed-length array could be of type "uintptr"
+ // and gimple disallows binary operations between "uintptr" and other
+ // integer types. FIXME.
+ Bexpression* length = NULL;
if (this->end_ == NULL || this->end_->is_nil_expression())
{
Expression* len = array_type->get_length(gogo, this->array_);
- length_tree = len->get_tree(context);
- if (length_tree == error_mark_node)
- return error_mark_node;
- length_tree = save_expr(length_tree);
+ length = tree_to_expr(len->get_tree(context));
+ length = gogo->backend()->convert_expression(int_btype, length, loc);
}
- tree capacity_tree = NULL_TREE;
+ Bexpression* capacity = NULL;
if (this->end_ != NULL)
{
Expression* cap = array_type->get_capacity(gogo, this->array_);
- capacity_tree = cap->get_tree(context);
- if (capacity_tree == error_mark_node)
- return error_mark_node;
- capacity_tree = save_expr(capacity_tree);
+ capacity = tree_to_expr(cap->get_tree(context));
+ capacity = gogo->backend()->convert_expression(int_btype, capacity, loc);
}
- tree cap_arg = capacity_tree;
+ Bexpression* cap_arg = capacity;
if (this->cap_ != NULL)
{
- cap_arg = this->cap_->get_tree(context);
- if (cap_arg == error_mark_node)
- return error_mark_node;
+ cap_arg = tree_to_expr(this->cap_->get_tree(context));
+ cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc);
}
- tree length_type = (length_tree != NULL_TREE
- ? TREE_TYPE(length_tree)
- : TREE_TYPE(cap_arg));
-
- 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)));
+ if (length == NULL)
+ length = cap_arg;
int code = (array_type->length() != NULL
? (this->end_ == NULL
@@ -10704,168 +10346,124 @@ Array_index_expression::do_get_tree(Translate_context* context)
: (this->end_ == NULL
? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS
: RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS));
- tree crash = gogo->runtime_error(code, loc)->get_tree(context);
+ Bexpression* crash =
+ tree_to_expr(gogo->runtime_error(code, loc)->get_tree(context));
+
+ Expression* bounds_check = Expression::check_bounds(this->start_, loc);
+ Bexpression* bad_index = tree_to_expr(bounds_check->get_tree(context));
+
+ Bexpression* start = tree_to_expr(this->start_->get_tree(context));
+ start = gogo->backend()->convert_expression(int_btype, start, loc);
+ Bexpression* start_too_large =
+ gogo->backend()->binary_expression((this->end_ == NULL
+ ? OPERATOR_GE
+ : OPERATOR_GT),
+ start,
+ (this->end_ == NULL
+ ? length
+ : capacity),
+ loc);
+ bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, start_too_large,
+ bad_index, 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);
+ // wrap the index check into START.
+ start =
+ gogo->backend()->conditional_expression(int_btype, bad_index,
+ crash, start, loc);
+ Bexpression* ret;
if (array_type->length() != NULL)
{
- // Fixed array.
- tree array_tree = this->array_->get_tree(context);
- if (array_tree == error_mark_node)
- return error_mark_node;
- return build4(ARRAY_REF, TREE_TYPE(type_tree), array_tree,
- start_tree, NULL_TREE, NULL_TREE);
+ Bexpression* array = tree_to_expr(this->array_->get_tree(context));
+ ret = gogo->backend()->array_index_expression(array, start, loc);
}
else
{
- // Open array.
- Expression* valptr =
+ // Slice.
+ Expression* valptr =
array_type->get_value_pointer(gogo, this->array_);
- tree values = valptr->get_tree(context);
- 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);
+ Bexpression* ptr = tree_to_expr(valptr->get_tree(context));
+ ptr = gogo->backend()->pointer_offset_expression(ptr, start, loc);
+ ret = gogo->backend()->indirect_expression(ptr, true, loc);
}
+ return expr_to_tree(ret);
}
// Array slice.
if (this->cap_ != NULL)
{
- if (!DECL_P(cap_arg))
- cap_arg = save_expr(cap_arg);
- if (!INTEGRAL_TYPE_P(TREE_TYPE(cap_arg)))
- cap_arg = convert_to_integer(length_type, cap_arg);
-
- bad_index = Expression::check_bounds(cap_arg, length_type, bad_index,
- loc);
- cap_arg = fold_convert_loc(loc.gcc_location(), length_type, cap_arg);
-
- tree bad_cap = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node,
- fold_build2_loc(loc.gcc_location(),
- LT_EXPR, boolean_type_node,
- cap_arg, start_tree),
- fold_build2_loc(loc.gcc_location(),
- GT_EXPR, boolean_type_node,
- cap_arg, capacity_tree));
- bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, bad_index, bad_cap);
- }
-
- tree end_tree;
+ bounds_check = Expression::check_bounds(this->cap_, loc);
+ Bexpression* bounds_bcheck =
+ tree_to_expr(bounds_check->get_tree(context));
+ bad_index =
+ gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
+ bad_index, loc);
+ cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc);
+
+ Bexpression* cap_too_small =
+ gogo->backend()->binary_expression(OPERATOR_LT, cap_arg, start, loc);
+ Bexpression* cap_too_large =
+ gogo->backend()->binary_expression(OPERATOR_GT, cap_arg, capacity, loc);
+ Bexpression* bad_cap =
+ gogo->backend()->binary_expression(OPERATOR_OROR, cap_too_small,
+ cap_too_large, loc);
+ bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_cap,
+ bad_index, loc);
+ }
+
+ Bexpression* end;
if (this->end_->is_nil_expression())
- end_tree = length_tree;
+ end = length;
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);
+ bounds_check = Expression::check_bounds(this->end_, loc);
+ Bexpression* bounds_bcheck =
+ tree_to_expr(bounds_check->get_tree(context));
- end_tree = fold_convert_loc(loc.gcc_location(), length_type, end_tree);
+ bad_index =
+ gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
+ bad_index, loc);
- 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, cap_arg));
- bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
- boolean_type_node, bad_index, bad_end);
+ end = tree_to_expr(this->end_->get_tree(context));
+ end = gogo->backend()->convert_expression(int_btype, end, loc);
+ Bexpression* end_too_small =
+ gogo->backend()->binary_expression(OPERATOR_LT, end, start, loc);
+ Bexpression* end_too_large =
+ gogo->backend()->binary_expression(OPERATOR_GT, end, cap_arg, loc);
+ Bexpression* bad_end =
+ gogo->backend()->binary_expression(OPERATOR_OROR, end_too_small,
+ end_too_large, loc);
+ bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_end,
+ bad_index, loc);
}
-
- 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);
-
Expression* valptr = array_type->get_value_pointer(gogo, this->array_);
- tree value_pointer = valptr->get_tree(context);
- if (value_pointer == error_mark_node)
- return error_mark_node;
+ Bexpression* val = tree_to_expr(valptr->get_tree(context));
+ val = gogo->backend()->pointer_offset_expression(val, start, loc);
- value_pointer = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR,
- TREE_TYPE(value_pointer),
- value_pointer, offset);
+ Bexpression* result_length =
+ gogo->backend()->binary_expression(OPERATOR_MINUS, end, start, loc);
- tree result_length_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR,
- length_type, end_tree, start_tree);
+ Bexpression* result_capacity =
+ gogo->backend()->binary_expression(OPERATOR_MINUS, cap_arg, start, loc);
- tree result_capacity_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR,
- length_type, cap_arg, 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;
+ Btype* struct_btype = this->type()->get_backend(gogo);
+ std::vector<Bexpression*> init;
+ init.push_back(val);
+ init.push_back(result_length);
+ init.push_back(result_capacity);
- 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;
+ Bexpression* ctor =
+ gogo->backend()->constructor_expression(struct_btype, init, loc);
+ Bexpression* ret =
+ gogo->backend()->conditional_expression(struct_btype, bad_index,
+ crash, ctor, loc);
- return fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(constructor),
- build3(COND_EXPR, void_type_node,
- bad_index, crash, NULL_TREE),
- constructor);
+ return expr_to_tree(ret);
}
// Dump ast representation for an array index expression.
@@ -10903,6 +10501,9 @@ class String_index_expression : public Expression
int
do_traverse(Traverse*);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
Type*
do_type();
@@ -10963,6 +10564,36 @@ String_index_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
+Expression*
+String_index_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ Temporary_statement* temp;
+ Location loc = this->location();
+ if (!this->string_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->string_, loc);
+ inserter->insert(temp);
+ this->string_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (!this->start_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->start_, loc);
+ inserter->insert(temp);
+ this->start_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (this->end_ != NULL
+ && !this->end_->is_nil_expression()
+ && !this->end_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->end_, loc);
+ inserter->insert(temp);
+ this->end_ = Expression::make_temporary_reference(temp, loc);
+ }
+
+ return this;
+}
+
// Return the type of a string index.
Type*
@@ -11049,112 +10680,87 @@ tree
String_index_expression::do_get_tree(Translate_context* context)
{
Location loc = this->location();
+ Expression* string_arg = this->string_;
+ if (this->string_->type()->points_to() != NULL)
+ string_arg = Expression::make_unary(OPERATOR_MULT, this->string_, loc);
- tree string_tree = this->string_->get_tree(context);
- if (string_tree == error_mark_node)
- return error_mark_node;
+ Expression* bad_index = Expression::check_bounds(this->start_, loc);
- 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);
+ int code = (this->end_ == NULL
+ ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS
+ : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS);
- tree length_tree = String_type::length_tree(context->gogo(), string_tree);
- length_tree = save_expr(length_tree);
+ Gogo* gogo = context->gogo();
+ Bexpression* crash =
+ tree_to_expr(gogo->runtime_error(code, loc)->get_tree(context));
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;
+ // It is possible that an error occurred earlier because the start index
+ // cannot be represented as an integer type. In this case, we shouldn't
+ // try casting the starting index into an integer since
+ // Type_conversion_expression will fail to get the backend representation.
+ // FIXME.
+ if (this->start_->type()->integer_type() == NULL
+ && !Type::are_convertible(int_type, this->start_->type(), NULL))
+ {
+ go_assert(saw_errors());
+ return error_mark_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);
+ Expression* start = Expression::make_cast(int_type, this->start_, loc);
- bad_index = Expression::check_bounds(start_tree, length_type, bad_index,
- loc);
+ if (this->end_ == NULL)
+ {
+ Expression* length =
+ Expression::make_string_info(this->string_, STRING_INFO_LENGTH, loc);
- start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree);
+ Expression* start_too_large =
+ Expression::make_binary(OPERATOR_GE, start, length, loc);
+ bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large,
+ bad_index, loc);
+ Expression* bytes =
+ Expression::make_string_info(this->string_, STRING_INFO_DATA, loc);
- 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)->get_tree(context);
+ Bexpression* bstart = tree_to_expr(start->get_tree(context));
+ Bexpression* ptr = tree_to_expr(bytes->get_tree(context));
+ ptr = gogo->backend()->pointer_offset_expression(ptr, bstart, loc);
+ Bexpression* index = gogo->backend()->indirect_expression(ptr, true, loc);
- if (this->end_ == NULL)
+ Btype* byte_btype = bytes->type()->points_to()->get_backend(gogo);
+ Bexpression* index_error = tree_to_expr(bad_index->get_tree(context));
+ Bexpression* ret =
+ gogo->backend()->conditional_expression(byte_btype, index_error,
+ crash, index, loc);
+ return expr_to_tree(ret);
+ }
+
+ Expression* end = NULL;
+ if (this->end_->is_nil_expression())
{
- 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);
+ mpz_t neg_one;
+ mpz_init_set_si(neg_one, -1);
+ end = Expression::make_integer(&neg_one, int_type, loc);
+ mpz_clear(neg_one);
}
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);
+ Expression* bounds_check = Expression::check_bounds(this->end_, loc);
+ bad_index =
+ Expression::make_binary(OPERATOR_OROR, bounds_check, bad_index, loc);
+ end = Expression::make_cast(int_type, this->end_, loc);
}
+
+ Expression* strslice = Runtime::make_call(Runtime::STRING_SLICE, loc, 3,
+ string_arg, start, end);
+ Bexpression* bstrslice = tree_to_expr(strslice->get_tree(context));
+
+ Btype* str_btype = strslice->type()->get_backend(gogo);
+ Bexpression* index_error = tree_to_expr(bad_index->get_tree(context));
+ Bexpression* ret =
+ gogo->backend()->conditional_expression(str_btype, index_error,
+ crash, bstrslice, loc);
+ return expr_to_tree(ret);
}
// Dump ast representation for a string index expression.
@@ -11199,6 +10805,44 @@ Map_index_expression::do_traverse(Traverse* traverse)
return Expression::traverse(&this->index_, traverse);
}
+// We need to pass in a pointer to the key, so flatten the index into a
+// temporary variable if it isn't already. The value pointer will be
+// dereferenced and checked for nil, so flatten into a temporary to avoid
+// recomputation.
+
+Expression*
+Map_index_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ Map_type* mt = this->get_map_type();
+ if (this->index_->type() != mt->key_type())
+ this->index_ = Expression::make_cast(mt->key_type(), this->index_,
+ this->location());
+
+ if (!this->index_->is_variable())
+ {
+ Temporary_statement* temp = Statement::make_temporary(NULL, this->index_,
+ this->location());
+ inserter->insert(temp);
+ this->index_ = Expression::make_temporary_reference(temp,
+ this->location());
+ }
+
+ if (this->value_pointer_ == NULL)
+ this->get_value_pointer(this->is_lvalue_);
+ if (!this->value_pointer_->is_variable())
+ {
+ Temporary_statement* temp =
+ Statement::make_temporary(NULL, this->value_pointer_,
+ this->location());
+ inserter->insert(temp);
+ this->value_pointer_ =
+ Expression::make_temporary_reference(temp, this->location());
+ }
+
+ return this;
+}
+
// Return the type of a map index.
Type*
@@ -11258,131 +10902,84 @@ 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);
+ {
+ go_assert(saw_errors());
+ return error_mark_node;
+ }
- tree val_type_tree = TREE_TYPE(TREE_TYPE(valptr));
+ go_assert(this->value_pointer_ != NULL
+ && this->value_pointer_->is_variable());
+ Bexpression* ret;
if (this->is_lvalue_)
- return build_fold_indirect_ref(valptr);
+ {
+ Expression* val =
+ Expression::make_unary(OPERATOR_MULT, this->value_pointer_,
+ this->location());
+ ret = tree_to_expr(val->get_tree(context));
+ }
else if (this->is_in_tuple_assignment_)
{
// Tuple_map_assignment_statement is responsible for using this
// appropriately.
- return valptr;
+ ret = tree_to_expr(this->value_pointer_->get_tree(context));
}
else
{
+ Location loc = this->location();
+
+ Expression* nil_check =
+ Expression::make_binary(OPERATOR_EQEQ, this->value_pointer_,
+ Expression::make_nil(loc), loc);
+ Bexpression* bnil_check = tree_to_expr(nil_check->get_tree(context));
+ Expression* val =
+ Expression::make_unary(OPERATOR_MULT, this->value_pointer_, loc);
+ Bexpression* bval = tree_to_expr(val->get_tree(context));
+
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));
+ ret = gogo->backend()->conditional_expression(val_btype, bnil_check,
+ val_zero, bval, loc);
}
+
+ return expr_to_tree(ret);
}
-// 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
+// Get an expression for the map index. This returns an expression 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)
+Expression*
+Map_index_expression::get_value_pointer(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
+ if (this->value_pointer_ == NULL)
{
- 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
+ Map_type* type = this->get_map_type();
+ if (type == NULL)
{
- TREE_READONLY(tmp) = 1;
- TREE_CONSTANT(tmp) = 1;
- DECL_INITIAL(tmp) = index_tree;
- make_tmp = NULL_TREE;
+ go_assert(saw_errors());
+ return Expression::make_error(this->location());
}
- 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);
+ Location loc = this->location();
+ Expression* map_ref = this->map_;
+ if (this->map_->type()->points_to() != NULL)
+ map_ref = Expression::make_unary(OPERATOR_MULT, map_ref, loc);
- 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;
+ Expression* index_ptr = Expression::make_unary(OPERATOR_AND, this->index_,
+ loc);
+ Expression* map_index =
+ Runtime::make_call(Runtime::MAP_INDEX, loc, 3,
+ map_ref, index_ptr,
+ Expression::make_boolean(insert, loc));
+
+ Type* val_type = type->val_type();
+ this->value_pointer_ =
+ Expression::make_unsafe_cast(Type::make_pointer_type(val_type),
+ map_index, this->location());
+ }
+ return this->value_pointer_;
}
// Dump ast representation for a map index expression
@@ -11841,7 +11438,7 @@ Interface_field_reference_expression::do_get_tree(Translate_context* context)
vals->push_back(this->expr_);
Expression* expr = Expression::make_struct_composite_literal(st, vals, loc);
- expr = Expression::make_heap_composite(expr, loc);
+ expr = Expression::make_heap_expression(expr, loc);
Bexpression* bclosure = tree_to_expr(expr->get_tree(context));
Expression* nil_check =
@@ -12193,15 +11790,13 @@ class Allocation_expression : public 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);
+ Gogo* gogo = context->gogo();
+ Location loc = this->location();
+ Expression* space = gogo->allocate_memory(this->type_, loc);
+ Bexpression* bspace = tree_to_expr(space->get_tree(context));
+ Btype* pbtype = gogo->backend()->pointer_type(this->type_->get_backend(gogo));
+ Bexpression* ret = gogo->backend()->convert_expression(pbtype, bspace, loc);
+ return expr_to_tree(ret);
}
// Dump ast representation for an allocation expression.
@@ -12453,64 +12048,38 @@ Struct_construction_expression::do_get_tree(Translate_context* context)
{
Gogo* gogo = context->gogo();
+ Btype* btype = this->type_->get_backend(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);
+ return expr_to_tree(gogo->backend()->zero_expression(btype));
- 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)
+ std::vector<Bexpression*> init;
+ for (Struct_field_list::const_iterator pf = fields->begin();
+ pf != fields->end();
+ ++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));
+ init.push_back(gogo->backend()->zero_expression(fbtype));
else if (*pv == NULL)
{
- val = expr_to_tree(gogo->backend()->zero_expression(fbtype));
+ init.push_back(gogo->backend()->zero_expression(fbtype));
++pv;
}
else
{
- val = Expression::convert_for_assignment(context, pf->type(),
- (*pv)->type(),
- (*pv)->get_tree(context),
- this->location());
+ Expression* val =
+ Expression::convert_for_assignment(gogo, pf->type(),
+ *pv, this->location());
+ init.push_back(tree_to_expr(val->get_tree(context)));
++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;
+ Bexpression* ret =
+ gogo->backend()->constructor_expression(btype, init, this->location());
+ return expr_to_tree(ret);
}
// Export a struct construction.
@@ -12555,7 +12124,7 @@ Expression::make_struct_composite_literal(Type* type, Expression_list* vals,
// Construct an array. This class is not used directly; instead we
// use the child classes, Fixed_array_construction_expression and
-// Open_array_construction_expression.
+// Slice_construction_expression.
class Array_construction_expression : public Expression
{
@@ -12608,9 +12177,9 @@ protected:
vals()
{ return this->vals_; }
- // Get a constructor tree for the array values.
- tree
- get_constructor_tree(Translate_context* context, tree type_tree);
+ // Get the backend constructor for the array values.
+ Bexpression*
+ get_constructor(Translate_context* context, Btype* btype);
void
do_dump_expression(Ast_dump_context*) const;
@@ -12723,16 +12292,17 @@ Array_construction_expression::do_check_types(Gogo*)
}
}
-// Get a constructor tree for the array values.
+// Get a constructor expression for the array values.
-tree
-Array_construction_expression::get_constructor_tree(Translate_context* context,
- tree type_tree)
+Bexpression*
+Array_construction_expression::get_constructor(Translate_context* context,
+ Btype* array_btype)
{
- 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;
+
+ std::vector<unsigned long> indexes;
+ std::vector<Bexpression*> vals;
+ Gogo* gogo = context->gogo();
if (this->vals_ != NULL)
{
size_t i = 0;
@@ -12745,45 +12315,32 @@ Array_construction_expression::get_constructor_tree(Translate_context* context,
{
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);
+ indexes.push_back(i);
else
- elt->index = size_int(*pi);
-
+ indexes.push_back(*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);
+ vals.push_back(zv);
}
else
{
- tree value_tree = (*pv)->get_tree(context);
- elt->value = Expression::convert_for_assignment(context,
- element_type,
- (*pv)->type(),
- value_tree,
- this->location());
+ Expression* val_expr =
+ Expression::convert_for_assignment(gogo, element_type, *pv,
+ this->location());
+ vals.push_back(tree_to_expr(val_expr->get_tree(context)));
}
- 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;
+ return gogo->backend()->array_constructor_expression(array_btype, indexes,
+ vals, this->location());
}
// Export an array construction.
@@ -12894,43 +12451,47 @@ 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));
+ return expr_to_tree(this->get_constructor(context, btype));
}
-// Construct an open array.
+// Construct a slice.
-class Open_array_construction_expression : public Array_construction_expression
+class Slice_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)
+ Slice_construction_expression(Type* type,
+ const std::vector<unsigned long>* indexes,
+ Expression_list* vals, Location location)
+ : Array_construction_expression(EXPRESSION_SLICE_CONSTRUCTION,
+ type, indexes, vals, location),
+ valtype_(NULL)
{ go_assert(type->is_slice_type()); }
protected:
- // Note that taking the address of an open array literal is invalid.
+ // Note that taking the address of a slice 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());
+ return new Slice_construction_expression(this->type(), this->indexes(),
+ (this->vals() == NULL
+ ? NULL
+ : this->vals()->copy()),
+ this->location());
}
tree
do_get_tree(Translate_context*);
+
+ private:
+ // The type of the values in this slice.
+ Type* valtype_;
};
-// Return a tree for constructing an open array.
+// Return a tree for constructing a slice.
tree
-Open_array_construction_expression::do_get_tree(Translate_context* context)
+Slice_construction_expression::do_get_tree(Translate_context* context)
{
Array_type* array_type = this->type()->array_type();
if (array_type == NULL)
@@ -12940,49 +12501,43 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
}
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;
+ if (this->valtype_ == NULL)
+ {
+ mpz_t lenval;
+ Expression* length;
+ if (this->vals() == NULL || this->vals()->empty())
+ mpz_init_set_ui(lenval, 0);
+ else
+ {
+ if (this->indexes() == NULL)
+ mpz_init_set_ui(lenval, this->vals()->size());
+ else
+ mpz_init_set_ui(lenval, this->indexes()->back() + 1);
+ }
+ Location loc = this->location();
+ Type* int_type = Type::lookup_integer_type("int");
+ length = Expression::make_integer(&lenval, int_type, loc);
+ mpz_clear(lenval);
+ this->valtype_ = Type::make_array_type(element_type, length);
+ }
tree values;
- tree length_tree;
+ Gogo* gogo = context->gogo();
+ Btype* val_btype = this->valtype_->get_backend(gogo);
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);
+ Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
+ Bexpression* zero = gogo->backend()->zero_expression(int_btype);
+ std::vector<unsigned long> index(1, 0);
+ std::vector<Bexpression*> val(1, zero);
+ Bexpression* ctor =
+ gogo->backend()->array_constructor_expression(val_btype, index, val,
+ this->location());
+ values = expr_to_tree(ctor);
}
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);
- }
+ values = expr_to_tree(this->get_constructor(context, val_btype));
if (values == error_mark_node)
return error_mark_node;
@@ -13030,10 +12585,9 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
}
else
{
- tree memsize = TYPE_SIZE_UNIT(TREE_TYPE(values));
- space = context->gogo()->allocate_memory(element_type, memsize,
- this->location());
- space = save_expr(space);
+ Expression* alloc =
+ context->gogo()->allocate_memory(this->valtype_, this->location());
+ space = save_expr(alloc->get_tree(context));
tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space);
tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
@@ -13042,7 +12596,7 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
set = build2(MODIFY_EXPR, void_type_node, ref, values);
}
- // Build a constructor for the open array.
+ // Build a constructor for the slice.
tree type_tree = type_to_tree(this->type()->get_backend(context->gogo()));
if (type_tree == error_mark_node)
@@ -13059,6 +12613,7 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
elt->index = field;
elt->value = fold_convert(TREE_TYPE(field), space);
+ tree length_tree = this->valtype_->array_type()->length()->get_tree(context);
elt = init->quick_push(empty);
field = DECL_CHAIN(field);
go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
@@ -13091,7 +12646,7 @@ 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);
+ return new Slice_construction_expression(type, NULL, vals, location);
}
// Construct a map.
@@ -13102,13 +12657,16 @@ class Map_construction_expression : public Expression
Map_construction_expression(Type* type, Expression_list* vals,
Location location)
: Expression(EXPRESSION_MAP_CONSTRUCTION, location),
- type_(type), vals_(vals)
+ type_(type), vals_(vals), element_type_(NULL), constructor_temp_(NULL)
{ go_assert(vals == NULL || vals->size() % 2 == 0); }
protected:
int
do_traverse(Traverse* traverse);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
Type*
do_type()
{ return this->type_; }
@@ -13140,6 +12698,10 @@ class Map_construction_expression : public Expression
Type* type_;
// The list of values.
Expression_list* vals_;
+ // The type of the key-value pair struct for each map element.
+ Struct_type* element_type_;
+ // A temporary reference to the variable storing the constructor initializer.
+ Temporary_statement* constructor_temp_;
};
// Traversal.
@@ -13155,6 +12717,69 @@ Map_construction_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
+// Flatten constructor initializer into a temporary variable since
+// we need to take its address for __go_construct_map.
+
+Expression*
+Map_construction_expression::do_flatten(Gogo* gogo, Named_object*,
+ Statement_inserter* inserter)
+{
+ if (!this->is_error_expression()
+ && this->vals_ != NULL
+ && !this->vals_->empty()
+ && this->constructor_temp_ == NULL)
+ {
+ Map_type* mt = this->type_->map_type();
+ Type* key_type = mt->key_type();
+ Type* val_type = mt->val_type();
+ this->element_type_ = Type::make_builtin_struct_type(2,
+ "__key", key_type,
+ "__val", val_type);
+
+ Expression_list* value_pairs = new Expression_list();
+ Location loc = this->location();
+
+ size_t i = 0;
+ for (Expression_list::const_iterator pv = this->vals_->begin();
+ pv != this->vals_->end();
+ ++pv, ++i)
+ {
+ Expression_list* key_value_pair = new Expression_list();
+ Expression* key =
+ Expression::convert_for_assignment(gogo, key_type, *pv, loc);
+
+ ++pv;
+ Expression* val =
+ Expression::convert_for_assignment(gogo, val_type, *pv, loc);
+
+ key_value_pair->push_back(key);
+ key_value_pair->push_back(val);
+ value_pairs->push_back(
+ Expression::make_struct_composite_literal(this->element_type_,
+ key_value_pair, loc));
+ }
+
+ mpz_t lenval;
+ mpz_init_set_ui(lenval, i);
+ Expression* element_count = Expression::make_integer(&lenval, NULL, loc);
+ mpz_clear(lenval);
+
+ Type* ctor_type =
+ Type::make_array_type(this->element_type_, element_count);
+ Expression* constructor =
+ new Fixed_array_construction_expression(ctor_type, NULL,
+ value_pairs, loc);
+
+ this->constructor_temp_ =
+ Statement::make_temporary(NULL, constructor, loc);
+ constructor->issue_nil_check();
+ this->constructor_temp_->set_is_address_taken();
+ inserter->insert(this->constructor_temp_);
+ }
+
+ return this;
+}
+
// Final type determination.
void
@@ -13216,167 +12841,53 @@ Map_construction_expression::do_check_types(Gogo*)
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)
+ if (this->is_error_expression())
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);
+ Location loc = this->location();
- bool is_constant = true;
size_t i = 0;
- tree valaddr;
- tree make_tmp;
-
+ Expression* ventries;
if (this->vals_ == NULL || this->vals_->empty())
- {
- valaddr = null_pointer_node;
- make_tmp = NULL_TREE;
- }
+ ventries = Expression::make_nil(loc);
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;
- }
+ go_assert(this->constructor_temp_ != NULL);
+ i = this->vals_->size() / 2;
- 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);
+ Expression* ctor_ref =
+ Expression::make_temporary_reference(this->constructor_temp_, loc);
+ ventries = Expression::make_unary(OPERATOR_AND, ctor_ref, loc);
}
- Bexpression* bdescriptor = mt->map_descriptor_pointer(gogo, loc);
- tree descriptor = expr_to_tree(bdescriptor);
-
- 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;
+ Map_type* mt = this->type_->map_type();
+ if (this->element_type_ == NULL)
+ this->element_type_ =
+ Type::make_builtin_struct_type(2,
+ "__key", mt->key_type(),
+ "__val", mt->val_type());
+ Expression* descriptor = Expression::make_map_descriptor(mt, loc);
+
+ Type* uintptr_t = Type::lookup_integer_type("uintptr");
+ mpz_t countval;
+ mpz_init_set_ui(countval, i);
+ Expression* count = Expression::make_integer(&countval, uintptr_t, loc);
+ mpz_clear(countval);
+
+ Expression* entry_size =
+ Expression::make_type_info(this->element_type_, TYPE_INFO_SIZE);
+
+ unsigned int field_index;
+ const Struct_field* valfield =
+ this->element_type_->find_local_field("__val", &field_index);
+ Expression* val_offset =
+ Expression::make_struct_field_offset(this->element_type_, valfield);
+ Expression* val_size =
+ Expression::make_type_info(mt->val_type(), TYPE_INFO_SIZE);
+
+ Expression* map_ctor =
+ Runtime::make_call(Runtime::CONSTRUCT_MAP, loc, 6, descriptor, count,
+ entry_size, val_offset, val_size, ventries);
+ return map_ctor->get_tree(context);
}
// Export an array construction.
@@ -13589,7 +13100,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function,
}
if (is_pointer)
- ret = Expression::make_heap_composite(ret, this->location());
+ ret = Expression::make_heap_expression(ret, this->location());
return ret;
}
@@ -14031,8 +13542,7 @@ Composite_literal_expression::make_array(
return new Fixed_array_construction_expression(type, indexes, vals,
location);
else
- return new Open_array_construction_expression(type, indexes, vals,
- location);
+ return new Slice_construction_expression(type, indexes, vals, location);
}
// Lower a map composite literal.
@@ -14112,7 +13622,7 @@ Expression::is_composite_literal() const
case EXPRESSION_COMPOSITE_LITERAL:
case EXPRESSION_STRUCT_CONSTRUCTION:
case EXPRESSION_FIXED_ARRAY_CONSTRUCTION:
- case EXPRESSION_OPEN_ARRAY_CONSTRUCTION:
+ case EXPRESSION_SLICE_CONSTRUCTION:
case EXPRESSION_MAP_CONSTRUCTION:
return true;
default:
@@ -14140,10 +13650,10 @@ Expression::is_nonconstant_composite_literal() const
static_cast<const Fixed_array_construction_expression*>(this);
return !pace->is_constant_array();
}
- case EXPRESSION_OPEN_ARRAY_CONSTRUCTION:
+ case EXPRESSION_SLICE_CONSTRUCTION:
{
- const Open_array_construction_expression *pace =
- static_cast<const Open_array_construction_expression*>(this);
+ const Slice_construction_expression *pace =
+ static_cast<const Slice_construction_expression*>(this);
return !pace->is_constant_array();
}
case EXPRESSION_MAP_CONSTRUCTION:
@@ -14195,6 +13705,21 @@ Type_guard_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
+Expression*
+Type_guard_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ if (!this->expr_->is_variable())
+ {
+ Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_,
+ this->location());
+ inserter->insert(temp);
+ this->expr_ =
+ Expression::make_temporary_reference(temp, this->location());
+ }
+ return this;
+}
+
// Check types of a type guard expression. The expression must have
// an interface type, but the actual type conversion is checked at run
// time.
@@ -14236,24 +13761,23 @@ Type_guard_expression::do_check_types(Gogo*)
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;
+ Expression* conversion;
if (this->type_->interface_type() != NULL)
- return Expression::convert_interface_to_interface(context, this->type_,
- this->expr_->type(),
- expr_tree, true,
- this->location());
+ conversion =
+ Expression::convert_interface_to_interface(this->type_, this->expr_,
+ true, this->location());
else
- return Expression::convert_for_assignment(context, this->type_,
- this->expr_->type(), expr_tree,
- this->location());
+ conversion =
+ Expression::convert_for_assignment(context->gogo(), this->type_,
+ this->expr_, this->location());
+
+ return conversion->get_tree(context);
}
// Dump ast representation for a type guard expression.
void
-Type_guard_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
+Type_guard_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
const
{
this->expr_->dump_expression(ast_dump_context);
@@ -14270,16 +13794,16 @@ Expression::make_type_guard(Expression* expr, Type* type,
return new Type_guard_expression(expr, type, location);
}
-// Class Heap_composite_expression.
+// Class Heap_expression.
-// When you take the address of a composite literal, it is allocated
+// When you take the address of an escaping expression, it is allocated
// on the heap. This class implements that.
-class Heap_composite_expression : public Expression
+class Heap_expression : public Expression
{
public:
- Heap_composite_expression(Expression* expr, Location location)
- : Expression(EXPRESSION_HEAP_COMPOSITE, location),
+ Heap_expression(Expression* expr, Location location)
+ : Expression(EXPRESSION_HEAP, location),
expr_(expr)
{ }
@@ -14299,8 +13823,8 @@ class Heap_composite_expression : public Expression
Expression*
do_copy()
{
- return Expression::make_heap_composite(this->expr_->copy(),
- this->location());
+ return Expression::make_heap_expression(this->expr_->copy(),
+ this->location());
}
tree
@@ -14316,38 +13840,45 @@ class Heap_composite_expression : public Expression
do_dump_expression(Ast_dump_context*) const;
private:
- // The composite literal which is being put on the heap.
+ // The expression which is being put on the heap.
Expression* expr_;
};
-// Return a tree which allocates a composite literal on the heap.
+// Return a tree which allocates an expression on the heap.
tree
-Heap_composite_expression::do_get_tree(Translate_context* context)
+Heap_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);
+
+ Expression* alloc =
+ Expression::make_allocation(this->expr_->type(), this->location());
+
+ Gogo* gogo = context->gogo();
+ Btype* btype = this->expr_->type()->get_backend(gogo);
+ size_t expr_size = gogo->backend()->type_size(btype);
+ tree space = alloc->get_tree(context);
+ if (expr_size == 0)
+ return 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),
+ tree ret = build2(COMPOUND_EXPR,
+ type_to_tree(this->type()->get_backend(gogo)),
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.
+// Dump ast representation for a heap expression.
void
-Heap_composite_expression::do_dump_expression(
+Heap_expression::do_dump_expression(
Ast_dump_context* ast_dump_context) const
{
ast_dump_context->ostream() << "&(";
@@ -14355,12 +13886,12 @@ Heap_composite_expression::do_dump_expression(
ast_dump_context->ostream() << ")";
}
-// Allocate a composite literal on the heap.
+// Allocate an expression on the heap.
Expression*
-Expression::make_heap_composite(Expression* expr, Location location)
+Expression::make_heap_expression(Expression* expr, Location location)
{
- return new Heap_composite_expression(expr, location);
+ return new Heap_expression(expr, location);
}
// Class Receive_expression.
@@ -14399,6 +13930,32 @@ Receive_expression::do_check_types(Gogo*)
}
}
+// Flattening for receive expressions creates a temporary variable to store
+// received data in for receives.
+
+Expression*
+Receive_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ Channel_type* channel_type = this->channel_->type()->channel_type();
+ if (channel_type == NULL)
+ {
+ go_assert(saw_errors());
+ return this;
+ }
+
+ Type* element_type = channel_type->element_type();
+ if (this->temp_receiver_ == NULL)
+ {
+ this->temp_receiver_ = Statement::make_temporary(element_type, NULL,
+ this->location());
+ this->temp_receiver_->set_is_address_taken();
+ inserter->insert(this->temp_receiver_);
+ }
+
+ return this;
+}
+
// Get a tree for a receive expression.
tree
@@ -14412,19 +13969,18 @@ Receive_expression::do_get_tree(Translate_context* context)
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);
+ Expression* recv_ref =
+ Expression::make_temporary_reference(this->temp_receiver_, loc);
+ Expression* recv_addr =
+ Expression::make_temporary_reference(this->temp_receiver_, loc);
+ recv_addr = Expression::make_unary(OPERATOR_AND, recv_addr, loc);
+ Expression* recv =
+ Runtime::make_call(Runtime::RECEIVE, loc, 3,
+ td, this->channel_, recv_addr);
+ recv = Expression::make_compound(recv, recv_ref, loc);
+ return recv->get_tree(context);
}
// Dump ast representation for a receive expression.
@@ -14725,6 +14281,101 @@ Expression::make_slice_info(Expression* slice, Slice_info slice_info,
return new Slice_info_expression(slice, slice_info, location);
}
+// An expression that represents a slice value: a struct with value pointer,
+// length, and capacity fields.
+
+class Slice_value_expression : public Expression
+{
+ public:
+ Slice_value_expression(Type* type, Expression* valptr, Expression* len,
+ Expression* cap, Location location)
+ : Expression(EXPRESSION_SLICE_VALUE, location),
+ type_(type), valptr_(valptr), len_(len), cap_(cap)
+ { }
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type()
+ { return this->type_; }
+
+ void
+ do_determine_type(const Type_context*)
+ { go_unreachable(); }
+
+ Expression*
+ do_copy()
+ {
+ return new Slice_value_expression(this->type_, this->valptr_->copy(),
+ this->len_->copy(), this->cap_->copy(),
+ this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The type of the slice value.
+ Type* type_;
+ // The pointer to the values in the slice.
+ Expression* valptr_;
+ // The length of the slice.
+ Expression* len_;
+ // The capacity of the slice.
+ Expression* cap_;
+};
+
+int
+Slice_value_expression::do_traverse(Traverse* traverse)
+{
+ if (Expression::traverse(&this->valptr_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->len_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
+tree
+Slice_value_expression::do_get_tree(Translate_context* context)
+{
+ std::vector<Bexpression*> vals(3);
+ vals[0] = tree_to_expr(this->valptr_->get_tree(context));
+ vals[1] = tree_to_expr(this->len_->get_tree(context));
+ vals[2] = tree_to_expr(this->cap_->get_tree(context));
+
+ Gogo* gogo = context->gogo();
+ Btype* btype = this->type_->get_backend(gogo);
+ Bexpression* ret =
+ gogo->backend()->constructor_expression(btype, vals, this->location());
+ return expr_to_tree(ret);
+}
+
+void
+Slice_value_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "slicevalue(";
+ ast_dump_context->ostream() << "values: ";
+ this->valptr_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ", length: ";
+ this->len_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ", capacity: ";
+ this->cap_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ")";
+}
+
+Expression*
+Expression::make_slice_value(Type* at, Expression* valptr, Expression* len,
+ Expression* cap, Location location)
+{
+ go_assert(at->is_slice_type());
+ return new Slice_value_expression(at, valptr, len, cap, location);
+}
// An expression that evaluates to some characteristic of a non-empty interface.
// This is used to access the method table or underlying object of an interface.
@@ -14733,7 +14384,7 @@ class Interface_info_expression : public Expression
{
public:
Interface_info_expression(Expression* iface, Interface_info iface_info,
- Location location)
+ Location location)
: Expression(EXPRESSION_INTERFACE_INFO, location),
iface_(iface), iface_info_(iface_info)
{ }
@@ -14779,9 +14430,12 @@ Interface_info_expression::do_type()
{
case INTERFACE_INFO_METHODS:
{
+ Type* pdt = Type::make_type_descriptor_ptr_type();
+ if (this->iface_->type()->interface_type()->is_empty())
+ return pdt;
+
Location loc = this->location();
Struct_field_list* sfl = new Struct_field_list();
- Type* pdt = Type::make_type_descriptor_ptr_type();
sfl->push_back(
Struct_field(Typed_identifier("__type_descriptor", pdt, loc)));
@@ -14855,11 +14509,13 @@ void
Interface_info_expression::do_dump_expression(
Ast_dump_context* ast_dump_context) const
{
+ bool is_empty = this->iface_->type()->interface_type()->is_empty();
ast_dump_context->ostream() << "interfaceinfo(";
this->iface_->dump_expression(ast_dump_context);
ast_dump_context->ostream() << ",";
ast_dump_context->ostream() <<
- (this->iface_info_ == INTERFACE_INFO_METHODS ? "methods"
+ (this->iface_info_ == INTERFACE_INFO_METHODS && !is_empty ? "methods"
+ : this->iface_info_ == INTERFACE_INFO_TYPE_DESCRIPTOR ? "type_descriptor"
: this->iface_info_ == INTERFACE_INFO_OBJECT ? "object"
: "unknown");
ast_dump_context->ostream() << ")";
@@ -14874,6 +14530,303 @@ Expression::make_interface_info(Expression* iface, Interface_info iface_info,
return new Interface_info_expression(iface, iface_info, location);
}
+// An expression that represents an interface value. The first field is either
+// a type descriptor for an empty interface or a pointer to the interface method
+// table for a non-empty interface. The second field is always the object.
+
+class Interface_value_expression : public Expression
+{
+ public:
+ Interface_value_expression(Type* type, Expression* first_field,
+ Expression* obj, Location location)
+ : Expression(EXPRESSION_INTERFACE_VALUE, location),
+ type_(type), first_field_(first_field), obj_(obj)
+ { }
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type()
+ { return this->type_; }
+
+ void
+ do_determine_type(const Type_context*)
+ { go_unreachable(); }
+
+ Expression*
+ do_copy()
+ {
+ return new Interface_value_expression(this->type_,
+ this->first_field_->copy(),
+ this->obj_->copy(), this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The type of the interface value.
+ Type* type_;
+ // The first field of the interface (either a type descriptor or a pointer
+ // to the method table.
+ Expression* first_field_;
+ // The underlying object of the interface.
+ Expression* obj_;
+};
+
+int
+Interface_value_expression::do_traverse(Traverse* traverse)
+{
+ if (Expression::traverse(&this->first_field_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->obj_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
+tree
+Interface_value_expression::do_get_tree(Translate_context* context)
+{
+ std::vector<Bexpression*> vals(2);
+ vals[0] = tree_to_expr(this->first_field_->get_tree(context));
+ vals[1] = tree_to_expr(this->obj_->get_tree(context));
+
+ Gogo* gogo = context->gogo();
+ Btype* btype = this->type_->get_backend(gogo);
+ Bexpression* ret =
+ gogo->backend()->constructor_expression(btype, vals, this->location());
+ return expr_to_tree(ret);
+}
+
+void
+Interface_value_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "interfacevalue(";
+ ast_dump_context->ostream() <<
+ (this->type_->interface_type()->is_empty()
+ ? "type_descriptor: "
+ : "methods: ");
+ this->first_field_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ", object: ";
+ this->obj_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ")";
+}
+
+Expression*
+Expression::make_interface_value(Type* type, Expression* first_value,
+ Expression* object, Location location)
+{
+ return new Interface_value_expression(type, first_value, object, location);
+}
+
+// An interface method table for a pair of types: an interface type and a type
+// that implements that interface.
+
+class Interface_mtable_expression : public Expression
+{
+ public:
+ Interface_mtable_expression(Interface_type* itype, Type* type,
+ bool is_pointer, Location location)
+ : Expression(EXPRESSION_INTERFACE_MTABLE, location),
+ itype_(itype), type_(type), is_pointer_(is_pointer),
+ method_table_type_(NULL), bvar_(NULL)
+ { }
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type();
+
+ bool
+ is_immutable() const
+ { return true; }
+
+ void
+ do_determine_type(const Type_context*)
+ { go_unreachable(); }
+
+ Expression*
+ do_copy()
+ {
+ return new Interface_mtable_expression(this->itype_, this->type_,
+ this->is_pointer_, this->location());
+ }
+
+ bool
+ do_is_addressable() const
+ { return true; }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The interface type for which the methods are defined.
+ Interface_type* itype_;
+ // The type to construct the interface method table for.
+ Type* type_;
+ // Whether this table contains the method set for the receiver type or the
+ // pointer receiver type.
+ bool is_pointer_;
+ // The type of the method table.
+ Type* method_table_type_;
+ // The backend variable that refers to the interface method table.
+ Bvariable* bvar_;
+};
+
+int
+Interface_mtable_expression::do_traverse(Traverse* traverse)
+{
+ if (Type::traverse(this->itype_, traverse) == TRAVERSE_EXIT
+ || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
+Type*
+Interface_mtable_expression::do_type()
+{
+ if (this->method_table_type_ != NULL)
+ return this->method_table_type_;
+
+ const Typed_identifier_list* interface_methods = this->itype_->methods();
+ go_assert(!interface_methods->empty());
+
+ Struct_field_list* sfl = new Struct_field_list;
+ Typed_identifier tid("__type_descriptor", Type::make_type_descriptor_ptr_type(),
+ this->location());
+ sfl->push_back(Struct_field(tid));
+ for (Typed_identifier_list::const_iterator p = interface_methods->begin();
+ p != interface_methods->end();
+ ++p)
+ sfl->push_back(Struct_field(*p));
+ this->method_table_type_ = Type::make_struct_type(sfl, this->location());
+ return this->method_table_type_;
+}
+
+tree
+Interface_mtable_expression::do_get_tree(Translate_context* context)
+{
+ Gogo* gogo = context->gogo();
+ Bexpression* ret;
+ Location loc = Linemap::predeclared_location();
+ if (this->bvar_ != NULL)
+ {
+ ret = gogo->backend()->var_expression(this->bvar_, this->location());
+ return expr_to_tree(ret);
+ }
+
+ const Typed_identifier_list* interface_methods = this->itype_->methods();
+ go_assert(!interface_methods->empty());
+
+ std::string mangled_name = ((this->is_pointer_ ? "__go_pimt__" : "__go_imt_")
+ + this->itype_->mangled_name(gogo)
+ + "__"
+ + this->type_->mangled_name(gogo));
+
+ // 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
+ && this->type_->named_type() != NULL
+ && this->type_->named_type()->named_object()->package() != NULL)
+ {
+ Btype* btype = this->type()->get_backend(gogo);
+ this->bvar_ =
+ gogo->backend()->immutable_struct_reference(mangled_name, btype, loc);
+ ret = gogo->backend()->var_expression(this->bvar_, this->location());
+ return expr_to_tree(ret);
+ }
+
+ // The first element is the type descriptor.
+ Type* td_type;
+ if (!this->is_pointer_)
+ td_type = this->type_;
+ else
+ td_type = Type::make_pointer_type(this->type_);
+
+ // Build an interface method table for a type: a type descriptor followed by a
+ // list of function pointers, one for each interface method. This is used for
+ // interfaces.
+ Expression_list* svals = new Expression_list();
+ svals->push_back(Expression::make_type_descriptor(td_type, loc));
+
+ Named_type* nt = this->type_->named_type();
+ Struct_type* st = this->type_->struct_type();
+ go_assert(nt != NULL || st != NULL);
+
+ for (Typed_identifier_list::const_iterator p = interface_methods->begin();
+ p != interface_methods->end();
+ ++p)
+ {
+ 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();
+
+ go_assert(no->is_function() || no->is_function_declaration());
+ svals->push_back(Expression::make_func_code_reference(no, loc));
+ }
+
+ Btype* btype = this->type()->get_backend(gogo);
+ Expression* mtable = Expression::make_struct_composite_literal(this->type(),
+ svals, loc);
+ Bexpression* ctor = tree_to_expr(mtable->get_tree(context));
+
+ bool is_public = has_hidden_methods && this->type_->named_type() != NULL;
+ this->bvar_ = gogo->backend()->immutable_struct(mangled_name, false,
+ !is_public, btype, loc);
+ gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false,
+ !is_public, btype, loc, ctor);
+ ret = gogo->backend()->var_expression(this->bvar_, loc);
+ return expr_to_tree(ret);
+}
+
+void
+Interface_mtable_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "__go_"
+ << (this->is_pointer_ ? "pimt__" : "imt_");
+ ast_dump_context->dump_type(this->itype_);
+ ast_dump_context->ostream() << "__";
+ ast_dump_context->dump_type(this->type_);
+}
+
+Expression*
+Expression::make_interface_mtable_ref(Interface_type* itype, Type* type,
+ bool is_pointer, Location location)
+{
+ return new Interface_mtable_expression(itype, type, is_pointer, location);
+}
+
// 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.
@@ -15082,12 +15035,14 @@ class Conditional_expression : public Expression
{}
protected:
+ int
+ do_traverse(Traverse*);
+
Type*
do_type();
void
- do_determine_type(const Type_context*)
- { }
+ do_determine_type(const Type_context*);
Expression*
do_copy()
@@ -15111,13 +15066,26 @@ class Conditional_expression : public Expression
Expression* else_;
};
+// Traversal.
+
+int
+Conditional_expression::do_traverse(Traverse* traverse)
+{
+ if (Expression::traverse(&this->cond_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->then_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->else_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
// Return the type of the conditional expression.
Type*
Conditional_expression::do_type()
{
Type* result_type = Type::make_void_type();
- if (this->then_->type() == this->else_->type())
+ if (Type::are_identical(this->then_->type(), this->else_->type(), false,
+ NULL))
result_type = this->then_->type();
else if (this->then_->is_nil_expression()
|| this->else_->is_nil_expression())
@@ -15127,6 +15095,16 @@ Conditional_expression::do_type()
return result_type;
}
+// Determine type for a conditional expression.
+
+void
+Conditional_expression::do_determine_type(const Type_context* context)
+{
+ this->cond_->determine_type_no_context();
+ this->then_->determine_type(context);
+ this->else_->determine_type(context);
+}
+
// Get the backend representation of a conditional expression.
tree
@@ -15167,6 +15145,108 @@ Expression::make_conditional(Expression* cond, Expression* then,
return new Conditional_expression(cond, then, else_expr, location);
}
+// Compound expressions.
+
+class Compound_expression : public Expression
+{
+ public:
+ Compound_expression(Expression* init, Expression* expr, Location location)
+ : Expression(EXPRESSION_COMPOUND, location), init_(init), expr_(expr)
+ {}
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type();
+
+ void
+ do_determine_type(const Type_context*);
+
+ Expression*
+ do_copy()
+ {
+ return new Compound_expression(this->init_->copy(), this->expr_->copy(),
+ this->location());
+ }
+
+ tree
+ do_get_tree(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The expression that is evaluated first and discarded.
+ Expression* init_;
+ // The expression that is evaluated and returned.
+ Expression* expr_;
+};
+
+// Traversal.
+
+int
+Compound_expression::do_traverse(Traverse* traverse)
+{
+ if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
+// Return the type of the compound expression.
+
+Type*
+Compound_expression::do_type()
+{
+ return this->expr_->type();
+}
+
+// Determine type for a compound expression.
+
+void
+Compound_expression::do_determine_type(const Type_context* context)
+{
+ this->init_->determine_type_no_context();
+ this->expr_->determine_type(context);
+}
+
+// Get the backend representation of a compound expression.
+
+tree
+Compound_expression::do_get_tree(Translate_context* context)
+{
+ Gogo* gogo = context->gogo();
+ Bexpression* binit = tree_to_expr(this->init_->get_tree(context));
+ Bstatement* init_stmt = gogo->backend()->expression_statement(binit);
+ Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context));
+ Bexpression* ret = gogo->backend()->compound_expression(init_stmt, bexpr,
+ this->location());
+ return expr_to_tree(ret);
+}
+
+// Dump ast representation of a conditional expression.
+
+void
+Compound_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "(";
+ ast_dump_context->dump_expression(this->init_);
+ ast_dump_context->ostream() << ",";
+ ast_dump_context->dump_expression(this->expr_);
+ ast_dump_context->ostream() << ") ";
+}
+
+// Make a compound expression.
+
+Expression*
+Expression::make_compound(Expression* init, Expression* expr, Location location)
+{
+ return new Compound_expression(init, expr, location);
+}
+
// Import an expression. This comes at the end in order to see the
// various class definitions.
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 99a0d0720eb..dc9ad71c820 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -74,6 +74,7 @@ class Expression
EXPRESSION_UNKNOWN_REFERENCE,
EXPRESSION_BOOLEAN,
EXPRESSION_STRING,
+ EXPRESSION_STRING_INFO,
EXPRESSION_INTEGER,
EXPRESSION_FLOAT,
EXPRESSION_COMPLEX,
@@ -95,19 +96,23 @@ class Expression
EXPRESSION_UNSAFE_CONVERSION,
EXPRESSION_STRUCT_CONSTRUCTION,
EXPRESSION_FIXED_ARRAY_CONSTRUCTION,
- EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
+ EXPRESSION_SLICE_CONSTRUCTION,
EXPRESSION_MAP_CONSTRUCTION,
EXPRESSION_COMPOSITE_LITERAL,
- EXPRESSION_HEAP_COMPOSITE,
+ EXPRESSION_HEAP,
EXPRESSION_RECEIVE,
EXPRESSION_TYPE_DESCRIPTOR,
EXPRESSION_TYPE_INFO,
EXPRESSION_SLICE_INFO,
+ EXPRESSION_SLICE_VALUE,
EXPRESSION_INTERFACE_INFO,
+ EXPRESSION_INTERFACE_VALUE,
+ EXPRESSION_INTERFACE_MTABLE,
EXPRESSION_STRUCT_FIELD_OFFSET,
EXPRESSION_MAP_DESCRIPTOR,
EXPRESSION_LABEL_ADDR,
- EXPRESSION_CONDITIONAL
+ EXPRESSION_CONDITIONAL,
+ EXPRESSION_COMPOUND
};
Expression(Expression_classification, Location);
@@ -188,6 +193,20 @@ class Expression
static Expression*
make_string(const std::string&, Location);
+ // Make an expression that evaluates to some characteristic of an string.
+ // For simplicity, the enum values must match the field indexes in the
+ // underlying struct.
+ enum String_info
+ {
+ // The underlying data in the string.
+ STRING_INFO_DATA,
+ // The length of the string.
+ STRING_INFO_LENGTH
+ };
+
+ static Expression*
+ make_string_info(Expression* string, String_info, Location);
+
// Make a character constant expression. TYPE should be NULL for an
// abstract type.
static Expression*
@@ -312,9 +331,9 @@ class Expression
static Expression*
make_slice_composite_literal(Type*, Expression_list*, Location);
- // Take a composite literal and allocate it on the heap.
+ // Take an expression and allocate it on the heap.
static Expression*
- make_heap_composite(Expression*, Location);
+ make_heap_expression(Expression*, Location);
// Make a receive expression. VAL is NULL for a unary receive.
static Receive_expression*
@@ -358,14 +377,20 @@ class Expression
static Expression*
make_slice_info(Expression* slice, Slice_info, Location);
+ // Make an expression for a slice value.
+ static Expression*
+ make_slice_value(Type*, Expression* valptr, Expression* len, Expression* cap,
+ Location);
- // Make an expression that evaluates to some characteristic of a
+ // Make an expression that evaluates to some characteristic of an
// interface. For simplicity, the enum values must match the field indexes
- // of a non-empty interface in the underlying struct.
+ // in the underlying struct.
enum Interface_info
{
+ // The type descriptor of an empty interface.
+ INTERFACE_INFO_TYPE_DESCRIPTOR = 0,
// The methods of an interface.
- INTERFACE_INFO_METHODS,
+ INTERFACE_INFO_METHODS = 0,
// The first argument to pass to an interface method.
INTERFACE_INFO_OBJECT
};
@@ -373,6 +398,17 @@ class Expression
static Expression*
make_interface_info(Expression* iface, Interface_info, Location);
+ // Make an expression for an interface value.
+ static Expression*
+ make_interface_value(Type*, Expression*, Expression*, Location);
+
+ // Make an expression that builds a reference to the interface method table
+ // for TYPE that satisfies interface ITYPE. IS_POINTER is true if this is a
+ // reference to the interface method table for the pointer receiver type.
+ static Expression*
+ make_interface_mtable_ref(Interface_type* itype, Type* type,
+ bool is_pointer, Location);
+
// 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.
@@ -393,6 +429,10 @@ class Expression
static Expression*
make_conditional(Expression*, Expression*, Expression*, Location);
+ // Make a compound expression.
+ static Expression*
+ make_compound(Expression*, Expression*, Location);
+
// Return the expression classification.
Expression_classification
classification() const
@@ -700,19 +740,19 @@ class Expression
tree
get_tree(Translate_context*);
- // Return a tree handling any conversions which must be done during
+ // Return an expression 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);
+ static Expression*
+ convert_for_assignment(Gogo*, Type* lhs_type, Expression* rhs,
+ Location location);
- // Return a tree converting a value of one interface type to another
+ // Return an expression 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);
+ static Expression*
+ convert_interface_to_interface(Type* lhs_type,
+ Expression* rhs, bool for_type_guard,
+ Location);
// Return a backend expression implementing the comparison LEFT OP RIGHT.
// TYPE is the type of both sides.
@@ -736,12 +776,10 @@ class 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);
+ // Return an expression which checks that VAL, of arbitrary integer type,
+ // is non-negative and is not more than the maximum integer value.
+ static Expression*
+ check_bounds(Expression* val, Location);
// Dump an expression to a dump constext.
void
@@ -881,17 +919,14 @@ class Expression
: NULL);
}
- static tree
- convert_type_to_interface(Translate_context*, Type*, Type*, tree,
- Location);
+ static Expression*
+ convert_type_to_interface(Type*, Expression*, Location);
- static tree
- get_interface_type_descriptor(Translate_context*, Type*, tree,
- Location);
+ static Expression*
+ get_interface_type_descriptor(Expression*);
- static tree
- convert_interface_to_type(Translate_context*, Type*, Type*, tree,
- Location);
+ static Expression*
+ convert_interface_to_type(Type*, Expression*, Location);
// The expression classification.
Expression_classification classification_;
@@ -1408,8 +1443,8 @@ class Call_expression : public Expression
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),
+ fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL),
+ call_temp_(NULL), is_varargs_(is_varargs), are_hidden_fields_ok_(false),
varargs_are_lowered_(false), types_are_determined_(false),
is_deferred_(false), issued_error_(false)
{ }
@@ -1489,6 +1524,9 @@ class Call_expression : public Expression
virtual Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
+ virtual Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
bool
do_discarding_value()
{ return true; }
@@ -1550,8 +1588,8 @@ class Call_expression : public Expression
interface_method_function(Interface_field_reference_expression*,
Expression**);
- tree
- set_results(Translate_context*, tree);
+ Bexpression*
+ set_results(Translate_context*, Bexpression*);
// The function to call.
Expression* fn_;
@@ -1563,8 +1601,10 @@ class Call_expression : public Expression
// 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_;
+ // The backend expression for the call, used for a call which returns a tuple.
+ Bexpression* call_;
+ // A temporary variable to store this call if the function returns a tuple.
+ Temporary_statement* call_temp_;
// 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.
@@ -1838,7 +1878,7 @@ class Map_index_expression : public Expression
Location location)
: Expression(EXPRESSION_MAP_INDEX, location),
map_(map), index_(index), is_lvalue_(false),
- is_in_tuple_assignment_(false)
+ is_in_tuple_assignment_(false), value_pointer_(NULL)
{ }
// Return the map.
@@ -1881,18 +1921,21 @@ class Map_index_expression : public Expression
set_is_in_tuple_assignment()
{ this->is_in_tuple_assignment_ = true; }
- // Return a tree for the map index. This returns a tree which
+ // Return an expression for the map index. This returns an expression 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);
+ Expression*
+ get_value_pointer(bool insert);
protected:
int
do_traverse(Traverse*);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
Type*
do_type();
@@ -1934,6 +1977,8 @@ class Map_index_expression : public Expression
bool is_lvalue_;
// Whether this is in a tuple assignment to a pair of values.
bool is_in_tuple_assignment_;
+ // A pointer to the value at this index.
+ Expression* value_pointer_;
};
// An expression which represents a method bound to its first
@@ -2230,6 +2275,9 @@ class Type_guard_expression : public Expression
int
do_traverse(Traverse* traverse);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
Type*
do_type()
{ return this->type_; }
@@ -2268,7 +2316,7 @@ class Receive_expression : public Expression
public:
Receive_expression(Expression* channel, Location location)
: Expression(EXPRESSION_RECEIVE, location),
- channel_(channel)
+ channel_(channel), temp_receiver_(NULL)
{ }
// Return the channel.
@@ -2288,6 +2336,9 @@ class Receive_expression : public Expression
Type*
do_type();
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
void
do_determine_type(const Type_context*)
{ this->channel_->determine_type_no_context(); }
@@ -2314,6 +2365,8 @@ class Receive_expression : public Expression
private:
// The channel from which we are receiving.
Expression* channel_;
+ // A temporary reference to the variable storing the received data.
+ Temporary_statement* temp_receiver_;
};
// A numeric constant. This is used both for untyped constants and
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index 1950090b9e0..e92acae7af4 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -636,10 +636,10 @@ class Var_init
{
public:
Var_init()
- : var_(NULL), init_(NULL_TREE)
+ : var_(NULL), init_(NULL)
{ }
- Var_init(Named_object* var, tree init)
+ Var_init(Named_object* var, Bstatement* init)
: var_(var), init_(init)
{ }
@@ -649,15 +649,15 @@ class Var_init
{ return this->var_; }
// Return the initialization expression.
- tree
+ Bstatement*
init() const
{ return this->init_; }
private:
// The variable being initialized.
Named_object* var_;
- // The initialization expression to run.
- tree init_;
+ // The initialization statement.
+ Bstatement* init_;
};
typedef std::list<Var_init> Var_inits;
@@ -868,15 +868,13 @@ Gogo::write_globals()
// initializer purely for its side effects.
bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
- tree var_init_tree = NULL_TREE;
+ Bstatement* var_init_stmt = NULL;
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)
+ Bexpression* var_binit = no->var_value()->get_init(this, NULL);
+ if (var_binit == NULL)
;
- else if (TREE_CONSTANT(init))
+ else if (TREE_CONSTANT(expr_to_tree(var_binit)))
{
if (expression_requires(no->var_value()->init(), NULL,
this->var_depends_on(no->var_value()),
@@ -885,17 +883,20 @@ Gogo::write_globals()
"initialization expression for %qs depends "
"upon itself",
no->message_name().c_str());
- this->backend()->global_variable_set_init(var,
- tree_to_expr(init));
+ this->backend()->global_variable_set_init(var, var_binit);
}
- 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 if (is_sink)
+ var_init_stmt =
+ this->backend()->expression_statement(var_binit);
else
- var_init_tree = fold_build2_loc(no->location().gcc_location(),
- MODIFY_EXPR, void_type_node,
- vec[i], init);
+ {
+ Location loc = no->var_value()->location();
+ Bexpression* var_expr =
+ this->backend()->var_expression(var, loc);
+ var_init_stmt =
+ this->backend()->assignment_statement(var_expr, var_binit,
+ loc);
+ }
}
else
{
@@ -907,19 +908,21 @@ Gogo::write_globals()
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);
+ Bvariable* var_decl = is_sink ? NULL : var;
+ var_init_stmt =
+ 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 (var_init_stmt != NULL)
{
if (no->var_value()->init() == NULL
&& !no->var_value()->has_pre_init())
- append_to_statement_list(var_init_tree, &var_init_stmt_list);
+ append_to_statement_list(stat_to_tree(var_init_stmt),
+ &var_init_stmt_list);
else
- var_inits.push_back(Var_init(no, var_init_tree));
+ var_inits.push_back(Var_init(no, var_init_stmt));
}
else if (this->var_depends_on(no->var_value()) != NULL)
{
@@ -927,7 +930,12 @@ Gogo::write_globals()
// 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));
+ Btype* int_btype =
+ Type::lookup_integer_type("int")->get_backend(this);
+ Bexpression* zero = this->backend()->zero_expression(int_btype);
+ Bstatement* zero_stmt =
+ this->backend()->expression_statement(zero);
+ var_inits.push_back(Var_init(no, zero_stmt));
}
if (!is_sink && no->var_value()->type()->has_pointer())
@@ -950,7 +958,7 @@ Gogo::write_globals()
for (Var_inits::const_iterator p = var_inits.begin();
p != var_inits.end();
++p)
- append_to_statement_list(p->init(), &init_stmt_list);
+ append_to_statement_list(stat_to_tree(p->init()), &init_stmt_list);
}
// After all the variables are initialized, call the "init"
@@ -1106,7 +1114,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
cfun->function_end_locus =
func->block()->end_location().gcc_location();
- func->build_tree(gogo, this);
+ func->build(gogo, this);
gimplify_function_tree(decl);
@@ -1139,84 +1147,6 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
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 the backend representation.
Bfunction*
@@ -1272,469 +1202,6 @@ Function::get_decl() const
return function_to_tree(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->get_decl();
- 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 we need a closure variable, fetch it by calling a runtime
- // function. The caller will have called __go_set_closure before
- // the function call.
- if (this->closure_var_ != NULL)
- {
- Bvariable* bvar =
- this->closure_var_->get_backend_variable(gogo, named_function);
- tree var_decl = var_to_tree(bvar);
- if (var_decl != error_mark_node)
- {
- go_assert(TREE_CODE(var_decl) == VAR_DECL);
- static tree get_closure_fndecl;
- tree get_closure = Gogo::call_builtin(&get_closure_fndecl,
- this->location_,
- "__go_get_closure",
- 0,
- ptr_type_node);
-
- // Mark the __go_get_closure function as pure, since it
- // depends only on the global variable g.
- DECL_PURE_P(get_closure_fndecl) = 1;
-
- get_closure = fold_convert_loc(this->location_.gcc_location(),
- TREE_TYPE(var_decl), get_closure);
- DECL_INITIAL(var_decl) = get_closure;
- DECL_CHAIN(var_decl) = declare_vars;
- declare_vars = var_decl;
- }
- }
-
- 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;
- }
-
- // If we created a descriptor for the function, make sure we emit it.
- if (this->descriptor_ != NULL)
- {
- Translate_context context(gogo, NULL, NULL, NULL);
- this->descriptor_->get_tree(&context);
- }
-}
-
-// 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->get_decl()), 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->get_decl()), 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->get_decl()). 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->get_decl()));
- 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;
- }
-}
-
// Build the descriptor for a function declaration. This won't
// necessarily happen if the package has just a declaration for the
// function and no other reference to it, but we may still need the
@@ -1834,38 +1301,6 @@ go_type_for_mode(enum machine_mode mode, int unsignedp)
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
@@ -1915,94 +1350,6 @@ Gogo::builtin_struct(tree* ptype, const char* struct_name, tree 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
@@ -2048,136 +1395,6 @@ Gogo::slice_constructor(tree slice_type_tree, tree values, tree count,
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);
-
- Location loc = Linemap::predeclared_location();
- Bexpression* tdp_bexpr = td_type->type_descriptor_pointer(this, loc);
- tree tdp = expr_to_tree(tdp_bexpr);
- 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();
- Bfunction* bf;
- if (no->is_function())
- bf = no->func_value()->get_or_make_decl(this, no);
- else if (no->is_function_declaration())
- bf = no->func_declaration_value()->get_or_make_decl(this, no);
- else
- go_unreachable();
- tree fndecl = build_fold_addr_expr(function_to_tree(bf));
-
- 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, and the table is for a
- // named type, 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 && type->named_type() != NULL)
- 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
@@ -2250,70 +1467,3 @@ Gogo::call_builtin(tree* pdecl, Location location, const char* name,
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));
- }
-}
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 9739f289f4d..6df4b6bf325 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -1005,6 +1005,10 @@ Label*
Gogo::add_label_definition(const std::string& label_name,
Location location)
{
+ // A label with a blank identifier is never declared or defined.
+ if (label_name == "_")
+ return NULL;
+
go_assert(!this->functions_.empty());
Function* func = this->functions_.back().function->func_value();
Label* label = func->add_label_definition(this, label_name, location);
@@ -3330,6 +3334,7 @@ Build_method_tables::type(Type* type)
Struct_type* st = type->struct_type();
if (nt != NULL || st != NULL)
{
+ Translate_context context(this->gogo_, NULL, NULL, NULL);
for (std::vector<Interface_type*>::const_iterator p =
this->interfaces_.begin();
p != this->interfaces_.end();
@@ -3343,8 +3348,8 @@ Build_method_tables::type(Type* type)
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);
+ nt->interface_method_table(*p, false)->get_tree(&context);
+ nt->interface_method_table(*p, true)->get_tree(&context);
}
}
else
@@ -3352,8 +3357,8 @@ Build_method_tables::type(Type* type)
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);
+ st->interface_method_table(*p, false)->get_tree(&context);
+ st->interface_method_table(*p, true)->get_tree(&context);
}
}
}
@@ -3361,6 +3366,28 @@ Build_method_tables::type(Type* type)
return TRAVERSE_CONTINUE;
}
+// Return an expression which allocates memory to hold values of type TYPE.
+
+Expression*
+Gogo::allocate_memory(Type* type, Location location)
+{
+ Btype* btype = type->get_backend(this);
+ size_t size = this->backend()->type_size(btype);
+ mpz_t size_val;
+ mpz_init_set_ui(size_val, size);
+ Type* uintptr = Type::lookup_integer_type("uintptr");
+ Expression* size_expr =
+ Expression::make_integer(&size_val, uintptr, location);
+
+ // If the package imports unsafe, then it may play games with
+ // pointers that look like integers.
+ bool use_new_pointers = this->imported_unsafe_ || type->has_pointer();
+ return Runtime::make_call((use_new_pointers
+ ? Runtime::NEW
+ : Runtime::NEW_NOPOINTERS),
+ location, 1, size_expr);
+}
+
// Traversal class used to check for return statements.
class Check_return_statements_traverse : public Traverse
@@ -4111,6 +4138,293 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no)
return this->fndecl_;
}
+// Build the backend representation for the function code.
+
+void
+Function::build(Gogo* gogo, Named_object* named_function)
+{
+ Translate_context context(gogo, named_function, NULL, NULL);
+
+ // A list of parameter variables for this function.
+ std::vector<Bvariable*> param_vars;
+
+ // Variables that need to be declared for this function and their
+ // initial values.
+ std::vector<Bvariable*> vars;
+ std::vector<Bexpression*> var_inits;
+ for (Bindings::const_definitions_iterator p =
+ this->block_->bindings()->begin_definitions();
+ p != this->block_->bindings()->end_definitions();
+ ++p)
+ {
+ Location loc = (*p)->location();
+ if ((*p)->is_variable() && (*p)->var_value()->is_parameter())
+ {
+ Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
+ Bvariable* parm_bvar = 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)
+ {
+ std::string name = (*p)->name() + ".pointer";
+ Type* var_type = (*p)->var_value()->type();
+ Variable* parm_var =
+ new Variable(Type::make_pointer_type(var_type), NULL, false,
+ true, false, loc);
+ Named_object* parm_no =
+ Named_object::make_variable(name, NULL, parm_var);
+ parm_bvar = parm_no->get_backend_variable(gogo, named_function);
+
+ vars.push_back(bvar);
+ Expression* parm_ref =
+ Expression::make_var_reference(parm_no, loc);
+ parm_ref = Expression::make_unary(OPERATOR_MULT, parm_ref, loc);
+ if ((*p)->var_value()->is_in_heap())
+ parm_ref = Expression::make_heap_expression(parm_ref, loc);
+ var_inits.push_back(tree_to_expr(parm_ref->get_tree(&context)));
+ }
+ 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.
+ std::string parm_name = (*p)->name() + ".param";
+ Variable* parm_var = new Variable((*p)->var_value()->type(), NULL,
+ false, true, false, loc);
+ Named_object* parm_no =
+ Named_object::make_variable(parm_name, NULL, parm_var);
+ parm_bvar = parm_no->get_backend_variable(gogo, named_function);
+
+ vars.push_back(bvar);
+ Expression* var_ref =
+ Expression::make_var_reference(parm_no, loc);
+ var_ref = Expression::make_heap_expression(var_ref, loc);
+ var_inits.push_back(tree_to_expr(var_ref->get_tree(&context)));
+ }
+ param_vars.push_back(parm_bvar);
+ }
+ else if ((*p)->is_result_variable())
+ {
+ Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
+
+ Type* type = (*p)->result_var_value()->type();
+ Bexpression* init;
+ if (!(*p)->result_var_value()->is_in_heap())
+ {
+ Btype* btype = type->get_backend(gogo);
+ init = gogo->backend()->zero_expression(btype);
+ }
+ else
+ {
+ Expression* alloc = Expression::make_allocation(type, loc);
+ init = tree_to_expr(alloc->get_tree(&context));
+ }
+
+ vars.push_back(bvar);
+ var_inits.push_back(init);
+ }
+ }
+ if (!gogo->backend()->function_set_parameters(this->fndecl_, param_vars))
+ {
+ go_assert(saw_errors());
+ return;
+ }
+
+ // If we need a closure variable, fetch it by calling a runtime
+ // function. The caller will have called __go_set_closure before
+ // the function call.
+ if (this->closure_var_ != NULL)
+ {
+ Bvariable* closure_bvar =
+ this->closure_var_->get_backend_variable(gogo, named_function);
+ vars.push_back(closure_bvar);
+
+ Expression* closure =
+ Runtime::make_call(Runtime::GET_CLOSURE, this->location_, 0);
+ var_inits.push_back(tree_to_expr(closure->get_tree(&context)));
+ }
+
+ if (this->block_ != NULL)
+ {
+ // Declare variables if necessary.
+ Bblock* var_decls = NULL;
+
+ Bstatement* defer_init = NULL;
+ if (!vars.empty() || this->defer_stack_ != NULL)
+ {
+ var_decls =
+ gogo->backend()->block(this->fndecl_, NULL, vars,
+ this->block_->start_location(),
+ this->block_->end_location());
+
+ if (this->defer_stack_ != NULL)
+ {
+ Translate_context dcontext(gogo, named_function, this->block_,
+ var_decls);
+ defer_init = this->defer_stack_->get_backend(&dcontext);
+ }
+ }
+
+ // Build the backend representation for all the statements in the
+ // function.
+ Translate_context context(gogo, named_function, NULL, NULL);
+ Bblock* code_block = this->block_->get_backend(&context);
+
+ // Initialize variables if necessary.
+ std::vector<Bstatement*> init;
+ go_assert(vars.size() == var_inits.size());
+ for (size_t i = 0; i < vars.size(); ++i)
+ {
+ Bstatement* init_stmt =
+ gogo->backend()->init_statement(vars[i], var_inits[i]);
+ init.push_back(init_stmt);
+ }
+ Bstatement* var_init = gogo->backend()->statement_list(init);
+
+ // Initialize all variables before executing this code block.
+ Bstatement* code_stmt = gogo->backend()->block_statement(code_block);
+ code_stmt = gogo->backend()->compound_statement(var_init, code_stmt);
+
+ // If we have a defer stack, initialize it at the start of a
+ // function.
+ Bstatement* except = NULL;
+ Bstatement* fini = NULL;
+ if (defer_init != NULL)
+ {
+ // Clean up the defer stack when we leave the function.
+ this->build_defer_wrapper(gogo, named_function, &except, &fini);
+
+ // Wrap the code for this function in an exception handler to handle
+ // defer calls.
+ code_stmt =
+ gogo->backend()->exception_handler_statement(code_stmt,
+ except, fini,
+ this->location_);
+ }
+
+ // Stick the code into the block we built for the receiver, if
+ // we built one.
+ if (var_decls != NULL)
+ {
+ std::vector<Bstatement*> code_stmt_list(1, code_stmt);
+ gogo->backend()->block_add_statements(var_decls, code_stmt_list);
+ code_stmt = gogo->backend()->block_statement(var_decls);
+ }
+
+ if (!gogo->backend()->function_set_body(this->fndecl_, code_stmt))
+ {
+ go_assert(saw_errors());
+ return;
+ }
+ }
+
+ // If we created a descriptor for the function, make sure we emit it.
+ if (this->descriptor_ != NULL)
+ {
+ Translate_context context(gogo, NULL, NULL, NULL);
+ this->descriptor_->get_tree(&context);
+ }
+}
+
+// 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,
+ Bstatement** except, Bstatement** 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.
+
+ std::vector<Bstatement*> stmts;
+ Expression* call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1,
+ this->defer_stack(end_loc));
+ Translate_context context(gogo, named_function, NULL, NULL);
+ Bexpression* defer = tree_to_expr(call->get_tree(&context));
+ stmts.push_back(gogo->backend()->expression_statement(defer));
+
+ Bstatement* ret_bstmt = this->return_value(gogo, named_function, end_loc);
+ if (ret_bstmt != NULL)
+ stmts.push_back(ret_bstmt);
+
+ go_assert(*except == NULL);
+ *except = gogo->backend()->statement_list(stmts);
+
+ call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1,
+ this->defer_stack(end_loc));
+ defer = tree_to_expr(call->get_tree(&context));
+
+ call = Runtime::make_call(Runtime::UNDEFER, end_loc, 1,
+ this->defer_stack(end_loc));
+ Bexpression* undefer = tree_to_expr(call->get_tree(&context));
+ Bstatement* function_defer =
+ gogo->backend()->function_defer_statement(this->fndecl_, undefer, defer,
+ end_loc);
+ stmts = std::vector<Bstatement*>(1, function_defer);
+ 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.
+
+ ret_bstmt = this->return_value(gogo, named_function, end_loc);
+ Bexpression* nil =
+ tree_to_expr(Expression::make_nil(end_loc)->get_tree(&context));
+ Bexpression* ret =
+ gogo->backend()->compound_expression(ret_bstmt, nil, end_loc);
+ Expression* ref =
+ Expression::make_temporary_reference(this->defer_stack_, end_loc);
+ Bexpression* bref = tree_to_expr(ref->get_tree(&context));
+ ret = gogo->backend()->conditional_expression(NULL, bref, ret, NULL,
+ end_loc);
+ stmts.push_back(gogo->backend()->expression_statement(ret));
+ }
+
+ go_assert(*fini == NULL);
+ *fini = gogo->backend()->statement_list(stmts);
+}
+
+// Return the statement that assigns values to this function's result struct.
+
+Bstatement*
+Function::return_value(Gogo* gogo, Named_object* named_function,
+ Location location) const
+{
+ const Typed_identifier_list* results = this->type_->results();
+ if (results == NULL || results->empty())
+ return NULL;
+
+ go_assert(this->results_ != NULL);
+ if (this->results_->size() != results->size())
+ {
+ go_assert(saw_errors());
+ return gogo->backend()->error_statement();
+ }
+
+ std::vector<Bexpression*> vals(results->size());
+ for (size_t i = 0; i < vals.size(); ++i)
+ {
+ Named_object* no = (*this->results_)[i];
+ Bvariable* bvar = no->get_backend_variable(gogo, named_function);
+ Bexpression* val = gogo->backend()->var_expression(bvar, location);
+ if (no->result_var_value()->is_in_heap())
+ val = gogo->backend()->indirect_expression(val, true, location);
+ vals[i] = val;
+ }
+ return gogo->backend()->return_statement(this->fndecl_, vals, location);
+}
+
// Class Block.
Block::Block(Block* enclosing, Location location)
@@ -4857,6 +5171,74 @@ Variable::determine_type()
}
}
+// Get the initial value of a variable. 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.
+
+Bexpression*
+Variable::get_init(Gogo* gogo, Named_object* function)
+{
+ go_assert(this->preinit_ == NULL);
+ Location loc = this->location();
+ 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 gogo->backend()->zero_expression(btype);
+ }
+ else
+ {
+ Translate_context context(gogo, function, NULL, NULL);
+ Expression* init = Expression::make_cast(this->type(), this->init_, loc);
+ return tree_to_expr(init->get_tree(&context));
+ }
+}
+
+// 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.
+
+Bstatement*
+Variable::get_init_block(Gogo* gogo, Named_object* function,
+ Bvariable* var_decl)
+{
+ go_assert(this->preinit_ != NULL);
+
+ // We want to add the variable assignment to the end of the preinit
+ // block.
+
+ Translate_context context(gogo, function, NULL, NULL);
+ Bblock* bblock = this->preinit_->get_backend(&context);
+
+ // It's possible to have pre-init statements without an initializer
+ // if the pre-init statements set the variable.
+ Bstatement* decl_init = NULL;
+ if (this->init_ != NULL)
+ {
+ if (var_decl == NULL)
+ {
+ Bexpression* init_bexpr =
+ tree_to_expr(this->init_->get_tree(&context));
+ decl_init = gogo->backend()->expression_statement(init_bexpr);
+ }
+ else
+ {
+ Location loc = this->location();
+ Expression* val_expr =
+ Expression::convert_for_assignment(gogo, this->type(),
+ this->init_, this->location());
+ Bexpression* val = tree_to_expr(val_expr->get_tree(&context));
+ Bexpression* var_ref = gogo->backend()->var_expression(var_decl, loc);
+ decl_init = gogo->backend()->assignment_statement(var_ref, val, loc);
+ }
+ }
+ Bstatement* block_stmt = gogo->backend()->block_statement(bblock);
+ if (decl_init != NULL)
+ block_stmt = gogo->backend()->compound_statement(block_stmt, decl_init);
+ return block_stmt;
+}
+
// Export the variable
void
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 3f2808781b7..3dc401d6955 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -612,34 +612,9 @@ class Gogo
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);
+ // Return an expression which allocates memory to hold values of type TYPE.
+ Expression*
+ allocate_memory(Type *type, Location);
private:
// During parsing, we keep a stack of functions. Each function on
@@ -687,11 +662,6 @@ class Gogo
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&);
-
// Type used to map import names to packages.
typedef std::map<std::string, Package*> Imports;
@@ -1119,14 +1089,14 @@ class Function
tree
get_decl() const;
- // Set the function decl to hold a tree of the function code.
+ // Set the function decl to hold a backend representation of the function
+ // code.
void
- build_tree(Gogo*, Named_object*);
+ build(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 the statement that assigns values to this function's result struct.
+ Bstatement*
+ return_value(Gogo*, Named_object*, Location) const;
// Get a tree for the variable holding the defer stack.
Expression*
@@ -1151,14 +1121,8 @@ class Function
// 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*);
+ build_defer_wrapper(Gogo*, Named_object*, Bstatement**, Bstatement**);
typedef std::vector<std::pair<Named_object*,
Location> > Closure_fields;
@@ -1531,16 +1495,16 @@ class Variable
get_backend_variable(Gogo*, Named_object*, const Package*,
const std::string&);
- // Get the initial value of the variable as a tree. This may only
+ // Get the initial value of the variable. This may only
// be called if has_pre_init() returns false.
- tree
- get_init_tree(Gogo*, Named_object* function);
+ Bexpression*
+ get_init(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);
+ Bstatement*
+ get_init_block(Gogo*, Named_object* function, Bvariable* decl);
// Export the variable.
void
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index 7614e6fc795..3d60171dde2 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -2955,7 +2955,7 @@ Parse::create_closure(Named_object* function, Enclosing_vars* enclosing_vars,
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);
+ return Expression::make_heap_expression(cv, location);
}
// PrimaryExpr = Operand { Selector | Index | Slice | TypeGuard | Call } .
@@ -3538,7 +3538,7 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
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);
+ expr = Expression::make_heap_expression(expr, location);
else if (op != OPERATOR_CHANOP)
expr = Expression::make_unary(op, expr, location);
else
@@ -3765,7 +3765,8 @@ Parse::labeled_stmt(const std::string& label_name, Location location)
{
// Mark the label as used to avoid a useless error about an
// unused label.
- label->set_is_used();
+ if (label != NULL)
+ label->set_is_used();
error_at(location, "missing statement after label");
this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index a303a50410f..8c6e82b2267 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -142,11 +142,8 @@ 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.
+DEF_GO_RUNTIME(RECEIVE, "__go_receive", 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),
@@ -208,7 +205,7 @@ DEF_GO_RUNTIME(RUNTIME_ERROR, "__go_runtime_error", P1(INT32), R0())
// Close.
-DEF_GO_RUNTIME(CLOSE, "__go_close", P1(CHAN), R0())
+DEF_GO_RUNTIME(CLOSE, "__go_builtin_close", P1(CHAN), R0())
// Copy.
@@ -233,6 +230,11 @@ DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P1(UINTPTR), R1(POINTER))
// Start a new goroutine.
DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0())
+// Get the function closure.
+DEF_GO_RUNTIME(GET_CLOSURE, "__go_get_closure", P0(), R1(POINTER))
+
+// Set the function closure.
+DEF_GO_RUNTIME(SET_CLOSURE, "__go_set_closure", P1(POINTER), R0())
// Defer a function.
DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0())
@@ -270,7 +272,7 @@ DEF_GO_RUNTIME(IFACEI2T2, "runtime.ifaceI2T2", P3(TYPE, IFACE, POINTER),
// 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())
+DEF_GO_RUNTIME(ASSERT_INTERFACE, "__go_assert_interface", P2(TYPE, TYPE), R1(POINTER))
// Convert one interface type to another. This is used for an
// assignment.
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index d195ab9845a..49a864faa44 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -264,8 +264,7 @@ 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);
+ Bexpression* binit = var->get_init(context->gogo(), context->function());
if (!var->is_in_heap())
{
@@ -638,13 +637,17 @@ Assignment_statement::do_check_types(Gogo*)
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 rhs_tree = this->rhs_->get_tree(context);
+ 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());
+ Expression* rhs =
+ Expression::convert_for_assignment(context->gogo(), this->lhs_->type(),
+ this->rhs_, this->location());
+ tree rhs_tree = rhs->get_tree(context);
return context->backend()->assignment_statement(tree_to_expr(lhs_tree),
tree_to_expr(rhs_tree),
this->location());
@@ -2187,7 +2190,7 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
location);
// Allocate the initialized struct on the heap.
- constructor = Expression::make_heap_composite(constructor, location);
+ constructor = Expression::make_heap_expression(constructor, location);
// Look up the thunk.
Named_object* named_thunk = gogo->lookup(thunk_name, NULL);
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 2148a1a43e6..91a535f01c8 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -3075,34 +3075,6 @@ String_type::do_get_backend(Gogo* gogo)
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*
@@ -4916,9 +4888,8 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const
// 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,
+Expression*
+Struct_type::interface_method_table(Interface_type* interface,
bool is_pointer)
{
std::pair<Struct_type*, Struct_type::Struct_method_table_pair*>
@@ -4937,7 +4908,7 @@ Struct_type::interface_method_table(Gogo* gogo,
ins.first->second = smtp;
}
- return Type::interface_method_table(gogo, this, interface, is_pointer,
+ return Type::interface_method_table(this, interface, is_pointer,
&smtp->first, &smtp->second);
}
@@ -8198,13 +8169,12 @@ Named_type::method_function(const std::string& name, bool* is_ambiguous) const
// 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)
+Expression*
+Named_type::interface_method_table(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 Type::interface_method_table(this, interface, is_pointer,
+ &this->interface_method_tables_,
+ &this->pointer_interface_method_tables_);
}
// Return whether a named type has any hidden fields.
@@ -9385,9 +9355,9 @@ Type::method_function(const Methods* methods, const std::string& name,
// 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,
+Expression*
+Type::interface_method_table(Type* type,
+ Interface_type *interface,
bool is_pointer,
Interface_method_tables** method_tables,
Interface_method_tables** pointer_tables)
@@ -9399,23 +9369,18 @@ Type::interface_method_table(Gogo* gogo, Type* type,
if (*pimt == NULL)
*pimt = new Interface_method_tables(5);
- std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
+ std::pair<Interface_type*, Expression*> val(interface, NULL);
std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
+ Location loc = Linemap::predeclared_location();
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);
+ go_assert(ins.first->second == NULL);
+ ins.first->second =
+ Expression::make_interface_mtable_ref(interface, type, is_pointer, loc);
}
-
- 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);
+ return Expression::make_unary(OPERATOR_AND, ins.first->second, loc);
}
// Look for field or method NAME for TYPE. Return an Expression for
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 5fda4e7285e..d2ca1bf27fb 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -1019,14 +1019,14 @@ class Type
// 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,
+ typedef Unordered_map_hash(Interface_type*, Expression*, 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,
+ static Expression*
+ interface_method_table(Type* type,
+ Interface_type *interface, bool is_pointer,
Interface_method_tables** method_tables,
Interface_method_tables** pointer_tables);
@@ -1688,14 +1688,6 @@ class String_type : public 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
@@ -2205,9 +2197,8 @@ class Struct_type : public Type
// 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);
+ Expression*
+ interface_method_table(Interface_type* interface, bool is_pointer);
// Traverse just the field types of a struct type.
int
@@ -2946,9 +2937,8 @@ class Named_type : public Type
// 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);
+ Expression*
+ interface_method_table(Interface_type* interface, bool is_pointer);
// Whether this type has any hidden fields.
bool
diff --git a/libgo/runtime/chan.c b/libgo/runtime/chan.c
index 1d9e6681d35..38a2aafc775 100644
--- a/libgo/runtime/chan.c
+++ b/libgo/runtime/chan.c
@@ -483,31 +483,10 @@ __go_send_big(ChanType *t, Hchan* c, byte* p)
runtime_chansend(t, c, p, nil, runtime_getcallerpc(&t));
}
-// The compiler generates a call to __go_receive_small to receive a
-// value 8 bytes or smaller.
-uint64
-__go_receive_small(ChanType *t, Hchan* c)
-{
- union {
- byte b[sizeof(uint64)];
- uint64 v;
- } u;
- byte *p;
-
- u.v = 0;
-#ifndef WORDS_BIGENDIAN
- p = u.b;
-#else
- p = u.b + sizeof(uint64) - t->__element_type->__size;
-#endif
- runtime_chanrecv(t, c, p, nil, nil);
- return u.v;
-}
-
-// The compiler generates a call to __go_receive_big to receive a
-// value larger than 8 bytes.
+// The compiler generates a call to __go_receive to receive a
+// value from a channel.
void
-__go_receive_big(ChanType *t, Hchan* c, byte* p)
+__go_receive(ChanType *t, Hchan* c, byte* p)
{
runtime_chanrecv(t, c, p, nil, nil);
}