mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-24 19:33:59 +08:00
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. From-SVN: r209393
This commit is contained in:
parent
88f592e3f4
commit
7035307e8f
@ -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
|
||||
|
447
gcc/go/go-gcc.cc
447
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"
|
||||
@ -234,6 +235,18 @@ class Gcc_backend : public Backend
|
||||
Bexpression*
|
||||
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);
|
||||
|
||||
@ -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 = ¶ms;
|
||||
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;
|
||||
|
@ -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.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user