aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8/gcc/go
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8/gcc/go')
-rw-r--r--gcc-4.8/gcc/go/ChangeLog23
-rw-r--r--gcc-4.8/gcc/go/go-gcc.cc87
-rw-r--r--gcc-4.8/gcc/go/go-lang.c4
-rw-r--r--gcc-4.8/gcc/go/gofrontend/backend.h34
-rw-r--r--gcc-4.8/gcc/go/gofrontend/expressions.cc151
-rw-r--r--gcc-4.8/gcc/go/gofrontend/expressions.h4
-rw-r--r--gcc-4.8/gcc/go/gofrontend/gogo-tree.cc276
-rw-r--r--gcc-4.8/gcc/go/gofrontend/gogo.cc172
-rw-r--r--gcc-4.8/gcc/go/gofrontend/gogo.h39
-rw-r--r--gcc-4.8/gcc/go/gofrontend/import.h5
-rw-r--r--gcc-4.8/gcc/go/gofrontend/lex.cc21
-rw-r--r--gcc-4.8/gcc/go/gofrontend/parse.cc2
-rw-r--r--gcc-4.8/gcc/go/gofrontend/runtime.cc7
-rw-r--r--gcc-4.8/gcc/go/gofrontend/runtime.def6
-rw-r--r--gcc-4.8/gcc/go/gofrontend/types.cc255
-rw-r--r--gcc-4.8/gcc/go/gofrontend/types.h37
16 files changed, 779 insertions, 344 deletions
diff --git a/gcc-4.8/gcc/go/ChangeLog b/gcc-4.8/gcc/go/ChangeLog
index 6c1504db5..e5860d7ff 100644
--- a/gcc-4.8/gcc/go/ChangeLog
+++ b/gcc-4.8/gcc/go/ChangeLog
@@ -1,3 +1,26 @@
+2014-05-22 Release Manager
+
+ * GCC 4.8.3 released.
+
+2013-12-11 Ian Lance Taylor <iant@google.com>
+
+ * go-lang.c (go_langhook_post_options): Disable sibling calls by
+ default.
+
+2013-10-16 Ian Lance Taylor <iant@google.com>
+
+ Bring in from mainline:
+
+ 2013-10-11 Chris Manghane <cmang@google.com>
+ * go-gcc.cc (Gcc_backend::function_code_expression): New
+ function.
+
+ 2013-10-10 Chris Manghane <cmang@google.com>
+ * go-gcc.cc (Backend::error_function): New function.
+ (Backend::function): New function.
+ (Backend::make_function): New function.
+ (function_to_tree): New function.
+
2013-10-16 Release Manager
* GCC 4.8.2 released.
diff --git a/gcc-4.8/gcc/go/go-gcc.cc b/gcc-4.8/gcc/go/go-gcc.cc
index fcfd41b34..81e9ad186 100644
--- a/gcc-4.8/gcc/go/go-gcc.cc
+++ b/gcc-4.8/gcc/go/go-gcc.cc
@@ -232,6 +232,9 @@ class Gcc_backend : public Backend
Bexpression*
convert_expression(Btype* type, Bexpression* expr, Location);
+ Bexpression*
+ function_code_expression(Bfunction*, Location);
+
// Statements.
Bstatement*
@@ -334,6 +337,17 @@ class Gcc_backend : public Backend
Bexpression*
label_address(Blabel*, Location);
+ // Functions.
+
+ Bfunction*
+ error_function()
+ { return this->make_function(error_mark_node); }
+
+ Bfunction*
+ 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);
+
private:
// Make a Bexpression from a tree.
Bexpression*
@@ -350,6 +364,10 @@ class Gcc_backend : public Backend
make_type(tree t)
{ return new Btype(t); }
+ Bfunction*
+ make_function(tree t)
+ { return new Bfunction(t); }
+
Btype*
fill_in_struct(Btype*, const std::vector<Btyped_identifier>&);
@@ -966,6 +984,19 @@ Gcc_backend::convert_expression(Btype* type, Bexpression* expr, Location)
return tree_to_expr(ret);
}
+// Get the address of a function.
+
+Bexpression*
+Gcc_backend::function_code_expression(Bfunction* bfunc, Location location)
+{
+ tree func = bfunc->get_tree();
+ if (func == error_mark_node)
+ return this->error_expression();
+
+ tree ret = build_fold_addr_expr_loc(location.gcc_location(), func);
+ return this->make_expression(ret);
+}
+
// An expression as a statement.
Bstatement*
@@ -1724,6 +1755,56 @@ Gcc_backend::label_address(Blabel* label, Location location)
return this->make_expression(ret);
}
+// Declare or define a new function.
+
+Bfunction*
+Gcc_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 location)
+{
+ tree functype = fntype->get_tree();
+ if (functype != error_mark_node)
+ {
+ gcc_assert(FUNCTION_POINTER_TYPE_P(functype));
+ functype = TREE_TYPE(functype);
+ }
+ tree id = get_identifier_from_string(name);
+ if (functype == error_mark_node || id == error_mark_node)
+ return this->error_function();
+
+ tree decl = build_decl(location.gcc_location(), FUNCTION_DECL, id, functype);
+ if (!asm_name.empty())
+ SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
+ if (is_visible)
+ TREE_PUBLIC(decl) = 1;
+ if (is_declaration)
+ DECL_EXTERNAL(decl) = 1;
+ else
+ {
+ tree restype = TREE_TYPE(functype);
+ tree resdecl =
+ build_decl(location.gcc_location(), RESULT_DECL, NULL_TREE, restype);
+ DECL_ARTIFICIAL(resdecl) = 1;
+ DECL_IGNORED_P(resdecl) = 1;
+ DECL_CONTEXT(resdecl) = decl;
+ DECL_RESULT(decl) = resdecl;
+ }
+ if (!is_inlinable)
+ DECL_UNINLINABLE(decl) = 1;
+ if (disable_split_stack)
+ {
+ tree attr = get_identifier("__no_split_stack__");
+ DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
+ }
+ if (in_unique_section)
+ resolve_unique_section(decl, 0, 1);
+
+ go_preserve_from_gc(decl);
+ return new Bfunction(decl);
+}
+
// The single backend.
static Gcc_backend gcc_backend;
@@ -1799,3 +1880,9 @@ var_to_tree(Bvariable* bv)
{
return bv->get_tree();
}
+
+tree
+function_to_tree(Bfunction* bf)
+{
+ return bf->get_tree();
+}
diff --git a/gcc-4.8/gcc/go/go-lang.c b/gcc-4.8/gcc/go/go-lang.c
index 659cd8ef7..7e92deb92 100644
--- a/gcc-4.8/gcc/go/go-lang.c
+++ b/gcc-4.8/gcc/go/go-lang.c
@@ -269,6 +269,10 @@ go_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED)
if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT)
flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD;
+ /* Tail call optimizations can confuse uses of runtime.Callers. */
+ if (!global_options_set.x_flag_optimize_sibling_calls)
+ global_options.x_flag_optimize_sibling_calls = 0;
+
/* Returning false means that the backend should be used. */
return false;
}
diff --git a/gcc-4.8/gcc/go/gofrontend/backend.h b/gcc-4.8/gcc/go/gofrontend/backend.h
index fa3e3cc68..ca997f08a 100644
--- a/gcc-4.8/gcc/go/gofrontend/backend.h
+++ b/gcc-4.8/gcc/go/gofrontend/backend.h
@@ -23,7 +23,7 @@ class Bexpression;
// The backend representation of a statement.
class Bstatement;
-// The backend representation of a function definition.
+// The backend representation of a function definition or declaration.
class Bfunction;
// The backend representation of a block.
@@ -266,6 +266,11 @@ class Backend
virtual Bexpression*
convert_expression(Btype* type, Bexpression* expr, Location) = 0;
+ // Create an expression for the address of a function. This is used to
+ // get the address of the code for a function.
+ virtual Bexpression*
+ function_code_expression(Bfunction*, Location) = 0;
+
// Statements.
// Create an error statement. This is used for cases which should
@@ -498,6 +503,32 @@ class Backend
// recover.
virtual Bexpression*
label_address(Blabel*, Location) = 0;
+
+ // Functions.
+
+ // Create an error function. This is used for cases which should
+ // not occur in a correct program, in order to keep the compilation
+ // going without crashing.
+ virtual Bfunction*
+ error_function() = 0;
+
+ // Declare or define a function of FNTYPE.
+ // NAME is the Go name of the function. ASM_NAME, if not the empty string, is
+ // the name that should be used in the symbol table; this will be non-empty if
+ // a magic extern comment is used.
+ // IS_VISIBLE is true if this function should be visible outside of the
+ // current compilation unit. IS_DECLARATION is true if this is a function
+ // declaration rather than a definition; the function definition will be in
+ // another compilation unit.
+ // IS_INLINABLE is true if the function can be inlined.
+ // DISABLE_SPLIT_STACK is true if this function may not split the stack; this
+ // is used for the implementation of recover.
+ // IN_UNIQUE_SECTION is true if this function should be put into a unique
+ // location if possible; this is used for field tracking.
+ virtual Bfunction*
+ 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;
};
// The backend interface has to define this function.
@@ -517,5 +548,6 @@ extern tree expr_to_tree(Bexpression*);
extern tree stat_to_tree(Bstatement*);
extern tree block_to_tree(Bblock*);
extern tree var_to_tree(Bvariable*);
+extern tree function_to_tree(Bfunction*);
#endif // !defined(GO_BACKEND_H)
diff --git a/gcc-4.8/gcc/go/gofrontend/expressions.cc b/gcc-4.8/gcc/go/gofrontend/expressions.cc
index d5e3a6762..3e54084ff 100644
--- a/gcc-4.8/gcc/go/gofrontend/expressions.cc
+++ b/gcc-4.8/gcc/go/gofrontend/expressions.cc
@@ -1219,7 +1219,7 @@ Func_expression::do_type()
// Get the tree for the code of a function expression.
-tree
+Bexpression*
Func_expression::get_code_pointer(Gogo* gogo, Named_object* no, Location loc)
{
Function_type* fntype;
@@ -1237,25 +1237,18 @@ Func_expression::get_code_pointer(Gogo* gogo, Named_object* no, Location loc)
error_at(loc,
"invalid use of special builtin function %qs; must be called",
no->message_name().c_str());
- return error_mark_node;
+ return gogo->backend()->error_expression();
}
- tree id = no->get_id(gogo);
- if (id == error_mark_node)
- return error_mark_node;
-
- tree fndecl;
+ Bfunction* fndecl;
if (no->is_function())
- fndecl = no->func_value()->get_or_make_decl(gogo, no, id);
+ fndecl = no->func_value()->get_or_make_decl(gogo, no);
else if (no->is_function_declaration())
- fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no, id);
+ fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no);
else
go_unreachable();
- if (fndecl == error_mark_node)
- return error_mark_node;
-
- return build_fold_addr_expr_loc(loc.gcc_location(), fndecl);
+ return gogo->backend()->function_code_expression(fndecl, loc);
}
// Get the tree for a function expression. This is used when we take
@@ -1492,8 +1485,10 @@ class Func_code_reference_expression : public Expression
tree
Func_code_reference_expression::do_get_tree(Translate_context* context)
{
- return Func_expression::get_code_pointer(context->gogo(), this->function_,
+ Bexpression* ret =
+ Func_expression::get_code_pointer(context->gogo(), this->function_,
this->location());
+ return expr_to_tree(ret);
}
// Make a reference to the code of a function.
@@ -3055,8 +3050,7 @@ class Type_conversion_expression : public Expression
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
bool
- do_is_constant() const
- { return this->expr_->is_constant(); }
+ do_is_constant() const;
bool
do_numeric_constant_value(Numeric_constant*) const;
@@ -3198,6 +3192,27 @@ Type_conversion_expression::do_lower(Gogo*, Named_object*,
return this;
}
+// Return whether a type conversion is a constant.
+
+bool
+Type_conversion_expression::do_is_constant() const
+{
+ if (!this->expr_->is_constant())
+ return false;
+
+ // A conversion to a type that may not be used as a constant is not
+ // a constant. For example, []byte(nil).
+ Type* type = this->type_;
+ if (type->integer_type() == NULL
+ && type->float_type() == NULL
+ && type->complex_type() == NULL
+ && !type->is_boolean_type()
+ && !type->is_string_type())
+ return false;
+
+ return true;
+}
+
// Return the constant numeric value if there is one.
bool
@@ -5586,6 +5601,15 @@ Binary_expression::do_determine_type(const Type_context* context)
subcontext.type = NULL;
}
+ if (this->op_ == OPERATOR_ANDAND || this->op_ == OPERATOR_OROR)
+ {
+ // For a logical operation, the context does not determine the
+ // types of the operands. The operands must be some boolean
+ // type but if the context has a boolean type they do not
+ // inherit it. See http://golang.org/issue/3924.
+ subcontext.type = NULL;
+ }
+
// Set the context for the left hand operand.
if (is_shift_op)
{
@@ -5967,6 +5991,43 @@ Binary_expression::do_get_tree(Translate_context* context)
right);
}
+ // For complex division Go wants slightly different results than the
+ // GCC library provides, so we have our own runtime routine.
+ if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL)
+ {
+ const char *name;
+ tree *pdecl;
+ Type* ctype;
+ static tree complex64_div_decl;
+ static tree complex128_div_decl;
+ switch (this->left_->type()->complex_type()->bits())
+ {
+ case 64:
+ name = "__go_complex64_div";
+ pdecl = &complex64_div_decl;
+ ctype = Type::lookup_complex_type("complex64");
+ break;
+ case 128:
+ name = "__go_complex128_div";
+ pdecl = &complex128_div_decl;
+ ctype = Type::lookup_complex_type("complex128");
+ break;
+ default:
+ go_unreachable();
+ }
+ Btype* cbtype = ctype->get_backend(gogo);
+ tree ctype_tree = type_to_tree(cbtype);
+ return Gogo::call_builtin(pdecl,
+ this->location(),
+ name,
+ 2,
+ ctype_tree,
+ ctype_tree,
+ fold_convert_loc(gccloc, ctype_tree, left),
+ type,
+ fold_convert_loc(gccloc, ctype_tree, right));
+ }
+
tree compute_type = excess_precision_type(type);
if (compute_type != NULL_TREE)
{
@@ -7191,6 +7252,15 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
if (this->code_ == BUILTIN_OFFSETOF)
{
Expression* arg = this->one_arg();
+
+ if (arg->bound_method_expression() != NULL
+ || arg->interface_field_reference_expression() != NULL)
+ {
+ this->report_error(_("invalid use of method value as argument "
+ "of Offsetof"));
+ return this;
+ }
+
Field_reference_expression* farg = arg->field_reference_expression();
while (farg != NULL)
{
@@ -7200,7 +7270,8 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
// it must not be reached through pointer indirections.
if (farg->expr()->deref() != farg->expr())
{
- this->report_error(_("argument of Offsetof implies indirection of an embedded field"));
+ this->report_error(_("argument of Offsetof implies "
+ "indirection of an embedded field"));
return this;
}
// Go up until we reach the original base.
@@ -7476,7 +7547,7 @@ Builtin_call_expression::check_int_value(Expression* e, bool is_length)
switch (nc.to_unsigned_long(&v))
{
case Numeric_constant::NC_UL_VALID:
- return true;
+ break;
case Numeric_constant::NC_UL_NOTINT:
error_at(e->location(), "non-integer %s argument to make",
is_length ? "len" : "cap");
@@ -7488,8 +7559,23 @@ Builtin_call_expression::check_int_value(Expression* e, bool is_length)
case Numeric_constant::NC_UL_BIG:
// We don't want to give a compile-time error for a 64-bit
// value on a 32-bit target.
- return true;
+ break;
}
+
+ mpz_t val;
+ if (!nc.to_int(&val))
+ go_unreachable();
+ int bits = mpz_sizeinbase(val, 2);
+ mpz_clear(val);
+ Type* int_type = Type::lookup_integer_type("int");
+ if (bits >= int_type->integer_type()->bits())
+ {
+ error_at(e->location(), "%s argument too large for make",
+ is_length ? "len" : "cap");
+ return false;
+ }
+
+ return true;
}
if (e->type()->integer_type() != NULL)
@@ -7595,6 +7681,8 @@ Find_call_expression::expression(Expression** pexpr)
bool
Builtin_call_expression::do_is_constant() const
{
+ if (this->is_error_expression())
+ return true;
switch (this->code_)
{
case BUILTIN_LEN:
@@ -9744,14 +9832,8 @@ Call_expression::do_get_tree(Translate_context* context)
}
tree fntype_tree = type_to_tree(fntype->get_backend(gogo));
- if (fntype_tree == error_mark_node)
- return error_mark_node;
- go_assert(POINTER_TYPE_P(fntype_tree));
- if (TREE_TYPE(fntype_tree) == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(TREE_TYPE(fntype_tree)) == RECORD_TYPE);
- tree fnfield_type = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(fntype_tree)));
- if (fnfield_type == error_mark_node)
+ 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));
@@ -9763,7 +9845,7 @@ Call_expression::do_get_tree(Translate_context* context)
if (func != NULL)
{
Named_object* no = func->named_object();
- fn = Func_expression::get_code_pointer(gogo, no, location);
+ fn = expr_to_tree(Func_expression::get_code_pointer(gogo, no, location));
if (!has_closure)
closure_tree = NULL_TREE;
else
@@ -10817,11 +10899,20 @@ String_index_expression::do_determine_type(const Type_context*)
void
String_index_expression::do_check_types(Gogo*)
{
- if (this->start_->type()->integer_type() == NULL)
+ Numeric_constant nc;
+ unsigned long v;
+ if (this->start_->type()->integer_type() == NULL
+ && !this->start_->type()->is_error()
+ && (!this->start_->numeric_constant_value(&nc)
+ || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT))
this->report_error(_("index must be integer"));
if (this->end_ != NULL
&& this->end_->type()->integer_type() == NULL
- && !this->end_->is_nil_expression())
+ && !this->end_->type()->is_error()
+ && !this->end_->is_nil_expression()
+ && !this->end_->is_error_expression()
+ && (!this->end_->numeric_constant_value(&nc)
+ || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT))
this->report_error(_("slice end must be integer"));
std::string sval;
diff --git a/gcc-4.8/gcc/go/gofrontend/expressions.h b/gcc-4.8/gcc/go/gofrontend/expressions.h
index bc7a25f76..35bfcfe8e 100644
--- a/gcc-4.8/gcc/go/gofrontend/expressions.h
+++ b/gcc-4.8/gcc/go/gofrontend/expressions.h
@@ -1514,8 +1514,8 @@ class Func_expression : public Expression
closure()
{ return this->closure_; }
- // Return a tree for the code for a function.
- static tree
+ // Return a backend expression for the code of a function.
+ static Bexpression*
get_code_pointer(Gogo*, Named_object* function, Location loc);
protected:
diff --git a/gcc-4.8/gcc/go/gofrontend/gogo-tree.cc b/gcc-4.8/gcc/go/gofrontend/gogo-tree.cc
index a95f29015..ef6c842c0 100644
--- a/gcc-4.8/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc-4.8/gcc/go/gofrontend/gogo-tree.cc
@@ -985,74 +985,6 @@ Gogo::write_globals()
delete[] vec;
}
-// Get a tree for the identifier for a named object.
-
-tree
-Named_object::get_id(Gogo* gogo)
-{
- go_assert(!this->is_variable() && !this->is_result_variable());
- std::string decl_name;
- if (this->is_function_declaration()
- && !this->func_declaration_value()->asm_name().empty())
- decl_name = this->func_declaration_value()->asm_name();
- else if (this->is_type()
- && Linemap::is_predeclared_location(this->type_value()->location()))
- {
- // We don't need the package name for builtin types.
- decl_name = Gogo::unpack_hidden_name(this->name_);
- }
- else
- {
- std::string package_name;
- if (this->package_ == NULL)
- package_name = gogo->package_name();
- else
- package_name = this->package_->package_name();
-
- // Note that this will be misleading if this is an unexported
- // method generated for an embedded imported type. In that case
- // the unexported method should have the package name of the
- // package from which it is imported, but we are going to give
- // it our package name. Fixing this would require knowing the
- // package name, but we only know the package path. It might be
- // better to use package paths here anyhow. This doesn't affect
- // the assembler code, because we always set that name in
- // Function::get_or_make_decl anyhow. FIXME.
-
- decl_name = package_name + '.' + Gogo::unpack_hidden_name(this->name_);
-
- Function_type* fntype;
- if (this->is_function())
- fntype = this->func_value()->type();
- else if (this->is_function_declaration())
- fntype = this->func_declaration_value()->type();
- else
- fntype = NULL;
- if (fntype != NULL && fntype->is_method())
- {
- decl_name.push_back('.');
- decl_name.append(fntype->receiver()->type()->mangled_name(gogo));
- }
- }
- if (this->is_type())
- {
- unsigned int index;
- const Named_object* in_function = this->type_value()->in_function(&index);
- if (in_function != NULL)
- {
- decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
- if (index > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", index);
- decl_name += '$';
- decl_name += buf;
- }
- }
- }
- return get_identifier_from_string(decl_name);
-}
-
// Get a tree for a named object.
tree
@@ -1067,11 +999,6 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
return error_mark_node;
}
- tree name;
- if (this->classification_ == NAMED_OBJECT_TYPE)
- name = NULL_TREE;
- else
- name = this->get_id(gogo);
tree decl;
switch (this->classification_)
{
@@ -1099,6 +1026,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
decl = error_mark_node;
else if (INTEGRAL_TYPE_P(TREE_TYPE(expr_tree)))
{
+ tree name = get_identifier_from_string(this->get_id(gogo));
decl = build_decl(named_constant->location().gcc_location(),
CONST_DECL, name, TREE_TYPE(expr_tree));
DECL_INITIAL(decl) = expr_tree;
@@ -1161,7 +1089,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
case NAMED_OBJECT_FUNC:
{
Function* func = this->u_.func_value;
- decl = func->get_or_make_decl(gogo, this, name);
+ decl = function_to_tree(func->get_or_make_decl(gogo, this));
if (decl != error_mark_node)
{
if (func->block() != NULL)
@@ -1286,123 +1214,12 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
return block_tree;
}
-// Get a tree for a function decl.
+// Get the backend representation.
-tree
-Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
+Bfunction*
+Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no)
{
- if (this->fndecl_ == NULL_TREE)
- {
- tree functype = type_to_tree(this->type_->get_backend(gogo));
-
- if (functype != error_mark_node)
- {
- // The type of a function comes back as a pointer to a
- // struct whose first field is the function, but we want the
- // real function type for a function declaration.
- go_assert(POINTER_TYPE_P(functype)
- && TREE_CODE(TREE_TYPE(functype)) == RECORD_TYPE);
- functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype)));
- go_assert(FUNCTION_POINTER_TYPE_P(functype));
- functype = TREE_TYPE(functype);
- }
-
- if (functype == error_mark_node)
- this->fndecl_ = error_mark_node;
- else
- {
- tree decl = build_decl(this->location().gcc_location(), FUNCTION_DECL,
- id, functype);
-
- this->fndecl_ = decl;
-
- if (no->package() != NULL)
- ;
- else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
- ;
- else if (Gogo::unpack_hidden_name(no->name()) == "init"
- && !this->type_->is_method())
- ;
- else if (Gogo::unpack_hidden_name(no->name()) == "main"
- && gogo->is_main_package())
- TREE_PUBLIC(decl) = 1;
- // Methods have to be public even if they are hidden because
- // they can be pulled into type descriptors when using
- // anonymous fields.
- else if (!Gogo::is_hidden_name(no->name())
- || this->type_->is_method())
- {
- TREE_PUBLIC(decl) = 1;
- std::string pkgpath = gogo->pkgpath_symbol();
- if (this->type_->is_method()
- && Gogo::is_hidden_name(no->name())
- && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
- {
- // This is a method we created for an unexported
- // method of an imported embedded type. We need to
- // use the pkgpath of the imported package to avoid
- // a possible name collision. See bug478 for a test
- // case.
- pkgpath = Gogo::hidden_name_pkgpath(no->name());
- pkgpath = Gogo::pkgpath_for_symbol(pkgpath);
- }
-
- std::string asm_name = pkgpath;
- asm_name.append(1, '.');
- asm_name.append(Gogo::unpack_hidden_name(no->name()));
- if (this->type_->is_method())
- {
- asm_name.append(1, '.');
- Type* rtype = this->type_->receiver()->type();
- asm_name.append(rtype->mangled_name(gogo));
- }
- SET_DECL_ASSEMBLER_NAME(decl,
- get_identifier_from_string(asm_name));
- }
-
- // Why do we have to do this in the frontend?
- tree restype = TREE_TYPE(functype);
- tree resdecl =
- build_decl(this->location().gcc_location(), RESULT_DECL, NULL_TREE,
- restype);
- DECL_ARTIFICIAL(resdecl) = 1;
- DECL_IGNORED_P(resdecl) = 1;
- DECL_CONTEXT(resdecl) = decl;
- DECL_RESULT(decl) = resdecl;
-
- // If a function calls the predeclared recover function, we
- // can't inline it, because recover behaves differently in a
- // function passed directly to defer. If this is a recover
- // thunk that we built to test whether a function can be
- // recovered, we can't inline it, because that will mess up
- // our return address comparison.
- if (this->calls_recover_ || this->is_recover_thunk_)
- DECL_UNINLINABLE(decl) = 1;
-
- // If this is a thunk created to call a function which calls
- // the predeclared recover function, we need to disable
- // stack splitting for the thunk.
- if (this->is_recover_thunk_)
- {
- tree attr = get_identifier("__no_split_stack__");
- DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
- }
-
- if (this->in_unique_section_)
- resolve_unique_section (decl, 0, 1);
-
- go_preserve_from_gc(decl);
- }
- }
- return this->fndecl_;
-}
-
-// Get a tree for a function declaration.
-
-tree
-Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
-{
- if (this->fndecl_ == NULL_TREE)
+ if (this->fndecl_ == NULL)
{
// Let Go code use an asm declaration to pick up a builtin
// function.
@@ -1412,38 +1229,15 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
builtin_functions.find(this->asm_name_);
if (p != builtin_functions.end())
{
- this->fndecl_ = p->second;
+ this->fndecl_ = tree_to_function(p->second);
return this->fndecl_;
}
}
- tree functype = type_to_tree(this->fntype_->get_backend(gogo));
-
- if (functype != error_mark_node)
- {
- // The type of a function comes back as a pointer to a
- // struct whose first field is the function, but we want the
- // real function type for a function declaration.
- go_assert(POINTER_TYPE_P(functype)
- && TREE_CODE(TREE_TYPE(functype)) == RECORD_TYPE);
- functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype)));
- go_assert(FUNCTION_POINTER_TYPE_P(functype));
- functype = TREE_TYPE(functype);
- }
-
- tree decl;
- if (functype == error_mark_node)
- decl = error_mark_node;
- else
- {
- decl = build_decl(this->location().gcc_location(), FUNCTION_DECL, id,
- functype);
- TREE_PUBLIC(decl) = 1;
- DECL_EXTERNAL(decl) = 1;
-
+ std::string asm_name;
if (this->asm_name_.empty())
{
- std::string asm_name = (no->package() == NULL
+ asm_name = (no->package() == NULL
? gogo->pkgpath_symbol()
: no->package()->pkgpath_symbol());
asm_name.append(1, '.');
@@ -1454,16 +1248,27 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
Type* rtype = this->fntype_->receiver()->type();
asm_name.append(rtype->mangled_name(gogo));
}
- SET_DECL_ASSEMBLER_NAME(decl,
- get_identifier_from_string(asm_name));
}
+
+ Btype* functype = this->fntype_->get_backend_fntype(gogo);
+ this->fndecl_ =
+ gogo->backend()->function(functype, no->get_id(gogo), asm_name,
+ true, true, true, false, false,
+ this->location());
}
- this->fndecl_ = decl;
- go_preserve_from_gc(decl);
- }
+
return this->fndecl_;
}
+// Return the function's decl after it has been built.
+
+tree
+Function::get_decl() const
+{
+ go_assert(this->fndecl_ != NULL);
+ 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
@@ -1558,7 +1363,7 @@ Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl)
void
Function::build_tree(Gogo* gogo, Named_object* named_function)
{
- tree fndecl = this->fndecl_;
+ tree fndecl = this->get_decl();
go_assert(fndecl != NULL_TREE);
tree params = NULL_TREE;
@@ -1796,7 +1601,7 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
set = NULL_TREE;
else
set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
- DECL_RESULT(this->fndecl_), retval);
+ 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);
@@ -1851,7 +1656,7 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
retval = this->return_value(gogo, named_function, end_loc,
&stmt_list);
set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
- DECL_RESULT(this->fndecl_), retval);
+ DECL_RESULT(this->get_decl()), retval);
ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR,
void_type_node, set);
@@ -1869,7 +1674,7 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
*fini = stmt_list;
}
-// Return the value to assign to DECL_RESULT(this->fndecl_). This may
+// 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.
@@ -1902,7 +1707,7 @@ Function::return_value(Gogo* gogo, Named_object* named_function,
}
else
{
- tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_));
+ tree rettype = TREE_TYPE(DECL_RESULT(this->get_decl()));
retval = create_tmp_var(rettype, "RESULT");
tree field = TYPE_FIELDS(rettype);
int index = 0;
@@ -2323,18 +2128,14 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
go_assert(m != NULL);
Named_object* no = m->named_object();
-
- tree fnid = no->get_id(this);
-
- tree fndecl;
+ Bfunction* bf;
if (no->is_function())
- fndecl = no->func_value()->get_or_make_decl(this, no, fnid);
+ bf = no->func_value()->get_or_make_decl(this, no);
else if (no->is_function_declaration())
- fndecl = no->func_declaration_value()->get_or_make_decl(this, no,
- fnid);
+ bf = no->func_declaration_value()->get_or_make_decl(this, no);
else
go_unreachable();
- fndecl = build_fold_addr_expr(fndecl);
+ tree fndecl = build_fold_addr_expr(function_to_tree(bf));
elt = pointers->quick_push(empty);
elt->index = size_int(i);
@@ -2353,10 +2154,11 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
TREE_CONSTANT(decl) = 1;
DECL_INITIAL(decl) = constructor;
- // If the interface type has hidden methods, then this is the only
- // definition of the table. Otherwise it is a comdat table which
- // may be defined in multiple packages.
- if (has_hidden_methods)
+ // 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
{
diff --git a/gcc-4.8/gcc/go/gofrontend/gogo.cc b/gcc-4.8/gcc/go/gofrontend/gogo.cc
index 9f918cb81..e16b0d3a5 100644
--- a/gcc-4.8/gcc/go/gofrontend/gogo.cc
+++ b/gcc-4.8/gcc/go/gofrontend/gogo.cc
@@ -2822,7 +2822,10 @@ Build_recover_thunks::function(Named_object* orig_no)
if (orig_fntype->is_varargs())
new_fntype->set_is_varargs();
- std::string name = orig_no->name() + "$recover";
+ std::string name = orig_no->name();
+ if (orig_fntype->is_method())
+ name += "$" + orig_fntype->receiver()->type()->mangled_name(gogo);
+ name += "$recover";
Named_object *new_no = gogo->start_function(name, new_fntype, false,
location);
Function *new_func = new_no->func_value();
@@ -2916,7 +2919,25 @@ Build_recover_thunks::function(Named_object* orig_no)
&& !orig_rec_no->var_value()->is_receiver());
orig_rec_no->var_value()->set_is_receiver();
- const std::string& new_receiver_name(orig_fntype->receiver()->name());
+ std::string new_receiver_name(orig_fntype->receiver()->name());
+ if (new_receiver_name.empty())
+ {
+ // Find the receiver. It was named "r.NNN" in
+ // Gogo::start_function.
+ for (Bindings::const_definitions_iterator p =
+ new_bindings->begin_definitions();
+ p != new_bindings->end_definitions();
+ ++p)
+ {
+ const std::string& pname((*p)->name());
+ if (pname[0] == 'r' && pname[1] == '.')
+ {
+ new_receiver_name = pname;
+ break;
+ }
+ }
+ go_assert(!new_receiver_name.empty());
+ }
Named_object* new_rec_no = new_bindings->lookup_local(new_receiver_name);
if (new_rec_no == NULL)
go_assert(saw_errors());
@@ -3320,7 +3341,8 @@ Function::Function(Function_type* type, Function* enclosing, Block* block,
closure_var_(NULL), block_(block), location_(location), labels_(),
local_type_count_(0), descriptor_(NULL), fndecl_(NULL), defer_stack_(NULL),
is_sink_(false), results_are_named_(false), nointerface_(false),
- calls_recover_(false), is_recover_thunk_(false), has_recover_thunk_(false),
+ is_unnamed_type_stub_method_(false), calls_recover_(false),
+ is_recover_thunk_(false), has_recover_thunk_(false),
in_unique_section_(false)
{
}
@@ -3819,6 +3841,81 @@ Function::import_func(Import* imp, std::string* pname,
*presults = results;
}
+// Get the backend representation.
+
+Bfunction*
+Function::get_or_make_decl(Gogo* gogo, Named_object* no)
+{
+ if (this->fndecl_ == NULL)
+ {
+ std::string asm_name;
+ bool is_visible = false;
+ if (no->package() != NULL)
+ ;
+ else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
+ ;
+ else if (Gogo::unpack_hidden_name(no->name()) == "init"
+ && !this->type_->is_method())
+ ;
+ else if (Gogo::unpack_hidden_name(no->name()) == "main"
+ && gogo->is_main_package())
+ is_visible = true;
+ // Methods have to be public even if they are hidden because
+ // they can be pulled into type descriptors when using
+ // anonymous fields.
+ else if (!Gogo::is_hidden_name(no->name())
+ || this->type_->is_method())
+ {
+ if (!this->is_unnamed_type_stub_method_)
+ is_visible = true;
+ std::string pkgpath = gogo->pkgpath_symbol();
+ if (this->type_->is_method()
+ && Gogo::is_hidden_name(no->name())
+ && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
+ {
+ // This is a method we created for an unexported
+ // method of an imported embedded type. We need to
+ // use the pkgpath of the imported package to avoid
+ // a possible name collision. See bug478 for a test
+ // case.
+ pkgpath = Gogo::hidden_name_pkgpath(no->name());
+ pkgpath = Gogo::pkgpath_for_symbol(pkgpath);
+ }
+
+ asm_name = pkgpath;
+ asm_name.append(1, '.');
+ asm_name.append(Gogo::unpack_hidden_name(no->name()));
+ if (this->type_->is_method())
+ {
+ asm_name.append(1, '.');
+ Type* rtype = this->type_->receiver()->type();
+ asm_name.append(rtype->mangled_name(gogo));
+ }
+ }
+
+ // If a function calls the predeclared recover function, we
+ // can't inline it, because recover behaves differently in a
+ // function passed directly to defer. If this is a recover
+ // thunk that we built to test whether a function can be
+ // recovered, we can't inline it, because that will mess up
+ // our return address comparison.
+ bool is_inlinable = !(this->calls_recover_ || this->is_recover_thunk_);
+
+ // If this is a thunk created to call a function which calls
+ // the predeclared recover function, we need to disable
+ // stack splitting for the thunk.
+ bool disable_split_stack = this->is_recover_thunk_;
+
+ Btype* functype = this->type_->get_backend_fntype(gogo);
+ this->fndecl_ =
+ gogo->backend()->function(functype, no->get_id(gogo), asm_name,
+ is_visible, false, is_inlinable,
+ disable_split_stack,
+ this->in_unique_section_, this->location());
+ }
+ return this->fndecl_;
+}
+
// Class Block.
Block::Block(Block* enclosing, Location location)
@@ -5110,6 +5207,75 @@ Named_object::get_backend_variable(Gogo* gogo, Named_object* function)
go_unreachable();
}
+
+// Return the external identifier for this object.
+
+std::string
+Named_object::get_id(Gogo* gogo)
+{
+ go_assert(!this->is_variable() && !this->is_result_variable());
+ std::string decl_name;
+ if (this->is_function_declaration()
+ && !this->func_declaration_value()->asm_name().empty())
+ decl_name = this->func_declaration_value()->asm_name();
+ else if (this->is_type()
+ && Linemap::is_predeclared_location(this->type_value()->location()))
+ {
+ // We don't need the package name for builtin types.
+ decl_name = Gogo::unpack_hidden_name(this->name_);
+ }
+ else
+ {
+ std::string package_name;
+ if (this->package_ == NULL)
+ package_name = gogo->package_name();
+ else
+ package_name = this->package_->package_name();
+
+ // Note that this will be misleading if this is an unexported
+ // method generated for an embedded imported type. In that case
+ // the unexported method should have the package name of the
+ // package from which it is imported, but we are going to give
+ // it our package name. Fixing this would require knowing the
+ // package name, but we only know the package path. It might be
+ // better to use package paths here anyhow. This doesn't affect
+ // the assembler code, because we always set that name in
+ // Function::get_or_make_decl anyhow. FIXME.
+
+ decl_name = package_name + '.' + Gogo::unpack_hidden_name(this->name_);
+
+ Function_type* fntype;
+ if (this->is_function())
+ fntype = this->func_value()->type();
+ else if (this->is_function_declaration())
+ fntype = this->func_declaration_value()->type();
+ else
+ fntype = NULL;
+ if (fntype != NULL && fntype->is_method())
+ {
+ decl_name.push_back('.');
+ decl_name.append(fntype->receiver()->type()->mangled_name(gogo));
+ }
+ }
+ if (this->is_type())
+ {
+ unsigned int index;
+ const Named_object* in_function = this->type_value()->in_function(&index);
+ if (in_function != NULL)
+ {
+ decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
+ if (index > 0)
+ {
+ char buf[30];
+ snprintf(buf, sizeof buf, "%u", index);
+ decl_name += '$';
+ decl_name += buf;
+ }
+ }
+ }
+ return decl_name;
+}
+
// Class Bindings.
Bindings::Bindings(Bindings* enclosing)
diff --git a/gcc-4.8/gcc/go/gofrontend/gogo.h b/gcc-4.8/gcc/go/gofrontend/gogo.h
index 23968d4a1..31b258d62 100644
--- a/gcc-4.8/gcc/go/gofrontend/gogo.h
+++ b/gcc-4.8/gcc/go/gofrontend/gogo.h
@@ -48,6 +48,7 @@ class Bstatement;
class Bblock;
class Bvariable;
class Blabel;
+class Bfunction;
// This file declares the basic classes used to hold the internal
// representation of Go which is built by the parser.
@@ -952,6 +953,15 @@ class Function
this->nointerface_ = true;
}
+ // Record that this function is a stub method created for an unnamed
+ // type.
+ void
+ set_is_unnamed_type_stub_method()
+ {
+ go_assert(this->is_method());
+ this->is_unnamed_type_stub_method_ = true;
+ }
+
// Add a new field to the closure variable.
void
add_closure_field(Named_object* var, Location loc)
@@ -1089,17 +1099,13 @@ class Function
this->descriptor_ = descriptor;
}
- // Return the function's decl given an identifier.
- tree
- get_or_make_decl(Gogo*, Named_object*, tree id);
+ // Return the backend representation.
+ Bfunction*
+ get_or_make_decl(Gogo*, Named_object*);
// Return the function's decl after it has been built.
tree
- get_decl() const
- {
- go_assert(this->fndecl_ != NULL);
- return this->fndecl_;
- }
+ get_decl() const;
// Set the function decl to hold a tree of the function code.
void
@@ -1170,7 +1176,7 @@ class Function
// The function descriptor, if any.
Expression* descriptor_;
// The function decl.
- tree fndecl_;
+ Bfunction* fndecl_;
// The defer stack variable. A pointer to this variable is used to
// distinguish the defer stack for one function from another. This
// is NULL unless we actually need a defer stack.
@@ -1181,6 +1187,9 @@ class Function
bool results_are_named_ : 1;
// True if this method should not be included in the type descriptor.
bool nointerface_ : 1;
+ // True if this function is a stub method created for an unnamed
+ // type.
+ bool is_unnamed_type_stub_method_ : 1;
// True if this function calls the predeclared recover function.
bool calls_recover_ : 1;
// True if this a thunk built for a function which calls recover.
@@ -1265,9 +1274,9 @@ class Function_declaration
has_descriptor() const
{ return this->descriptor_ != NULL; }
- // Return a decl for the function given an identifier.
- tree
- get_or_make_decl(Gogo*, Named_object*, tree id);
+ // Return a backend representation.
+ Bfunction*
+ get_or_make_decl(Gogo*, Named_object*);
// If there is a descriptor, build it into the backend
// representation.
@@ -1290,7 +1299,7 @@ class Function_declaration
// The function descriptor, if any.
Expression* descriptor_;
// The function decl if needed.
- tree fndecl_;
+ Bfunction* fndecl_;
};
// A variable.
@@ -2181,8 +2190,8 @@ class Named_object
Bvariable*
get_backend_variable(Gogo*, Named_object* function);
- // Return a tree for the external identifier for this object.
- tree
+ // Return the external identifier for this object.
+ std::string
get_id(Gogo*);
// Return a tree representing this object.
diff --git a/gcc-4.8/gcc/go/gofrontend/import.h b/gcc-4.8/gcc/go/gofrontend/import.h
index c6844cda8..9917937e4 100644
--- a/gcc-4.8/gcc/go/gofrontend/import.h
+++ b/gcc-4.8/gcc/go/gofrontend/import.h
@@ -149,6 +149,11 @@ class Import
location() const
{ return this->location_; }
+ // Return the package we are importing.
+ Package*
+ package() const
+ { return this->package_; }
+
// Return the next character.
int
peek_char()
diff --git a/gcc-4.8/gcc/go/gofrontend/lex.cc b/gcc-4.8/gcc/go/gofrontend/lex.cc
index 22a1f6e2a..d03c4bde2 100644
--- a/gcc-4.8/gcc/go/gofrontend/lex.cc
+++ b/gcc-4.8/gcc/go/gofrontend/lex.cc
@@ -873,7 +873,28 @@ Lex::gather_identifier()
&& (cc < 'a' || cc > 'z')
&& cc != '_'
&& (cc < '0' || cc > '9'))
+ {
+ // Check for an invalid character here, as we get better
+ // error behaviour if we swallow them as part of the
+ // identifier we are building.
+ if ((cc >= ' ' && cc < 0x7f)
+ || cc == '\t'
+ || cc == '\r'
+ || cc == '\n')
break;
+
+ this->lineoff_ = p - this->linebuf_;
+ error_at(this->location(),
+ "invalid character 0x%x in identifier",
+ cc);
+ if (!has_non_ascii_char)
+ {
+ buf.assign(pstart, p - pstart);
+ has_non_ascii_char = true;
+ }
+ if (!Lex::is_invalid_identifier(buf))
+ buf.append("$INVALID$");
+ }
++p;
if (is_first)
{
diff --git a/gcc-4.8/gcc/go/gofrontend/parse.cc b/gcc-4.8/gcc/go/gofrontend/parse.cc
index 498125bb2..9c7d8277e 100644
--- a/gcc-4.8/gcc/go/gofrontend/parse.cc
+++ b/gcc-4.8/gcc/go/gofrontend/parse.cc
@@ -744,6 +744,8 @@ Parse::signature(Typed_identifier* receiver, Location location)
return NULL;
Parse::Names names;
+ if (receiver != NULL)
+ names[receiver->name()] = receiver;
if (params != NULL)
this->check_signature_names(params, &names);
if (results != NULL)
diff --git a/gcc-4.8/gcc/go/gofrontend/runtime.cc b/gcc-4.8/gcc/go/gofrontend/runtime.cc
index ecc508d0d..3b0f18807 100644
--- a/gcc-4.8/gcc/go/gofrontend/runtime.cc
+++ b/gcc-4.8/gcc/go/gofrontend/runtime.cc
@@ -42,6 +42,8 @@ enum Runtime_function_type
RFT_RUNE,
// Go type float64, C type double.
RFT_FLOAT64,
+ // Go type complex64, C type __complex float.
+ RFT_COMPLEX64,
// Go type complex128, C type __complex double.
RFT_COMPLEX128,
// Go type string, C type struct __go_string.
@@ -126,6 +128,10 @@ runtime_function_type(Runtime_function_type bft)
t = Type::lookup_float_type("float64");
break;
+ case RFT_COMPLEX64:
+ t = Type::lookup_complex_type("complex64");
+ break;
+
case RFT_COMPLEX128:
t = Type::lookup_complex_type("complex128");
break;
@@ -216,6 +222,7 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
case RFT_UINTPTR:
case RFT_RUNE:
case RFT_FLOAT64:
+ case RFT_COMPLEX64:
case RFT_COMPLEX128:
case RFT_STRING:
case RFT_POINTER:
diff --git a/gcc-4.8/gcc/go/gofrontend/runtime.def b/gcc-4.8/gcc/go/gofrontend/runtime.def
index 0d3fd3c43..a303a5041 100644
--- a/gcc-4.8/gcc/go/gofrontend/runtime.def
+++ b/gcc-4.8/gcc/go/gofrontend/runtime.def
@@ -68,6 +68,12 @@ DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__go_string_to_int_array",
P1(STRING), R1(SLICE))
+// Complex division.
+DEF_GO_RUNTIME(COMPLEX64_DIV, "__go_complex64_div",
+ P2(COMPLEX64, COMPLEX64), R1(COMPLEX64))
+DEF_GO_RUNTIME(COMPLEX128_DIV, "__go_complex128_div",
+ P2(COMPLEX128, COMPLEX128), R1(COMPLEX128))
+
// Make a slice.
DEF_GO_RUNTIME(MAKESLICE1, "__go_make_slice1", P2(TYPE, UINTPTR), R1(SLICE))
DEF_GO_RUNTIME(MAKESLICE2, "__go_make_slice2", P3(TYPE, UINTPTR, UINTPTR),
diff --git a/gcc-4.8/gcc/go/gofrontend/types.cc b/gcc-4.8/gcc/go/gofrontend/types.cc
index e1d68e743..9bc356a73 100644
--- a/gcc-4.8/gcc/go/gofrontend/types.cc
+++ b/gcc-4.8/gcc/go/gofrontend/types.cc
@@ -1834,7 +1834,9 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name,
bloc);
gogo->start_block(bloc);
- if (this->struct_type() != NULL)
+ if (name != NULL && name->real_type()->named_type() != NULL)
+ this->write_named_hash(gogo, name, hash_fntype, equal_fntype);
+ else if (this->struct_type() != NULL)
this->struct_type()->write_hash_function(gogo, name, hash_fntype,
equal_fntype);
else if (this->array_type() != NULL)
@@ -1852,7 +1854,9 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name,
false, bloc);
gogo->start_block(bloc);
- if (this->struct_type() != NULL)
+ if (name != NULL && name->real_type()->named_type() != NULL)
+ this->write_named_equal(gogo, name);
+ else if (this->struct_type() != NULL)
this->struct_type()->write_equal_function(gogo, name);
else if (this->array_type() != NULL)
this->array_type()->write_equal_function(gogo, name);
@@ -1865,6 +1869,100 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name,
gogo->finish_function(bloc);
}
+// Write a hash function that simply calls the hash function for a
+// named type. This is used when one named type is defined as
+// another. This ensures that this case works when the other named
+// type is defined in another package and relies on calling hash
+// functions defined only in that package.
+
+void
+Type::write_named_hash(Gogo* gogo, Named_type* name,
+ Function_type* hash_fntype, Function_type* equal_fntype)
+{
+ Location bloc = Linemap::predeclared_location();
+
+ Named_type* base_type = name->real_type()->named_type();
+ go_assert(base_type != NULL);
+
+ // The pointer to the type we are going to hash. This is an
+ // unsafe.Pointer.
+ Named_object* key_arg = gogo->lookup("key", NULL);
+ go_assert(key_arg != NULL);
+
+ // The size of the type we are going to hash.
+ Named_object* keysz_arg = gogo->lookup("key_size", NULL);
+ go_assert(keysz_arg != NULL);
+
+ Named_object* hash_fn;
+ Named_object* equal_fn;
+ name->real_type()->type_functions(gogo, base_type, hash_fntype, equal_fntype,
+ &hash_fn, &equal_fn);
+
+ // Call the hash function for the base type.
+ Expression* key_ref = Expression::make_var_reference(key_arg, bloc);
+ Expression* keysz_ref = Expression::make_var_reference(keysz_arg, bloc);
+ Expression_list* args = new Expression_list();
+ args->push_back(key_ref);
+ args->push_back(keysz_ref);
+ Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc);
+ Expression* call = Expression::make_call(func, args, false, bloc);
+
+ // Return the hash of the base type.
+ Expression_list* vals = new Expression_list();
+ vals->push_back(call);
+ Statement* s = Statement::make_return_statement(vals, bloc);
+ gogo->add_statement(s);
+}
+
+// Write an equality function that simply calls the equality function
+// for a named type. This is used when one named type is defined as
+// another. This ensures that this case works when the other named
+// type is defined in another package and relies on calling equality
+// functions defined only in that package.
+
+void
+Type::write_named_equal(Gogo* gogo, Named_type* name)
+{
+ Location bloc = Linemap::predeclared_location();
+
+ // The pointers to the types we are going to compare. These have
+ // type unsafe.Pointer.
+ Named_object* key1_arg = gogo->lookup("key1", NULL);
+ Named_object* key2_arg = gogo->lookup("key2", NULL);
+ go_assert(key1_arg != NULL && key2_arg != NULL);
+
+ Named_type* base_type = name->real_type()->named_type();
+ go_assert(base_type != NULL);
+
+ // Build temporaries with the base type.
+ Type* pt = Type::make_pointer_type(base_type);
+
+ Expression* ref = Expression::make_var_reference(key1_arg, bloc);
+ ref = Expression::make_cast(pt, ref, bloc);
+ Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc);
+ gogo->add_statement(p1);
+
+ ref = Expression::make_var_reference(key2_arg, bloc);
+ ref = Expression::make_cast(pt, ref, bloc);
+ Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc);
+ gogo->add_statement(p2);
+
+ // Compare the values for equality.
+ Expression* t1 = Expression::make_temporary_reference(p1, bloc);
+ t1 = Expression::make_unary(OPERATOR_MULT, t1, bloc);
+
+ Expression* t2 = Expression::make_temporary_reference(p2, bloc);
+ t2 = Expression::make_unary(OPERATOR_MULT, t2, bloc);
+
+ Expression* cond = Expression::make_binary(OPERATOR_EQEQ, t1, t2, bloc);
+
+ // Return the equality comparison.
+ Expression_list* vals = new Expression_list();
+ vals->push_back(cond);
+ Statement* s = Statement::make_return_statement(vals, bloc);
+ gogo->add_statement(s);
+}
+
// Return a composite literal for the type descriptor for a plain type
// of kind RUNTIME_TYPE_KIND named NAME.
@@ -2164,26 +2262,9 @@ Type::method_constructor(Gogo*, Type* method_type,
++p;
go_assert(p->is_field_name("typ"));
- if (!only_value_methods && m->is_value_method())
- {
- // This is a value method on a pointer type. Change the type of
- // the method to use a pointer receiver. The implementation
- // always uses a pointer receiver anyhow.
- Type* rtype = mtype->receiver()->type();
- Type* prtype = Type::make_pointer_type(rtype);
- Typed_identifier* receiver =
- new Typed_identifier(mtype->receiver()->name(), prtype,
- mtype->receiver()->location());
- mtype = Type::make_function_type(receiver,
- (mtype->parameters() == NULL
- ? NULL
- : mtype->parameters()->copy()),
- (mtype->results() == NULL
- ? NULL
- : mtype->results()->copy()),
- mtype->location());
- }
- vals->push_back(Expression::make_type_descriptor(mtype, bloc));
+ bool want_pointer_receiver = !only_value_methods && m->is_value_method();
+ nonmethod_type = mtype->copy_with_receiver_as_param(want_pointer_receiver);
+ vals->push_back(Expression::make_type_descriptor(nonmethod_type, bloc));
++p;
go_assert(p->is_field_name("tfn"));
@@ -3383,18 +3464,10 @@ Function_type::do_hash_for_method(Gogo* gogo) const
// Get the backend representation for a function type.
Btype*
-Function_type::do_get_backend(Gogo* gogo)
+Function_type::get_backend_fntype(Gogo* gogo)
{
- // When we do anything with a function value other than call it, it
- // is represented as a pointer to a struct whose first field is the
- // actual function. So that is what we return as the type of a Go
- // function.
-
- Location loc = this->location();
- Btype* struct_type =
- gogo->backend()->placeholder_struct_type("__go_descriptor", loc);
- Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type);
-
+ if (this->fnbtype_ == NULL)
+ {
Backend::Btyped_identifier breceiver;
if (this->receiver_ != NULL)
{
@@ -3414,8 +3487,8 @@ Function_type::do_get_backend(Gogo* gogo)
{
bparameters.resize(this->parameters_->size());
size_t i = 0;
- for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
- p != this->parameters_->end();
+ for (Typed_identifier_list::const_iterator p =
+ this->parameters_->begin(); p != this->parameters_->end();
++p, ++i)
{
bparameters[i].name = Gogo::unpack_hidden_name(p->name());
@@ -3430,8 +3503,8 @@ Function_type::do_get_backend(Gogo* gogo)
{
bresults.resize(this->results_->size());
size_t i = 0;
- for (Typed_identifier_list::const_iterator p = this->results_->begin();
- p != this->results_->end();
+ for (Typed_identifier_list::const_iterator p =
+ this->results_->begin(); p != this->results_->end();
++p, ++i)
{
bresults[i].name = Gogo::unpack_hidden_name(p->name());
@@ -3441,11 +3514,33 @@ Function_type::do_get_backend(Gogo* gogo)
go_assert(i == bresults.size());
}
- Btype* fntype = gogo->backend()->function_type(breceiver, bparameters,
- bresults, loc);
+ this->fnbtype_ = gogo->backend()->function_type(breceiver, bparameters,
+ bresults,
+ this->location());
+
+ }
+
+ return this->fnbtype_;
+}
+
+// Get the backend representation for a Go function type.
+
+Btype*
+Function_type::do_get_backend(Gogo* gogo)
+{
+ // When we do anything with a function value other than call it, it
+ // is represented as a pointer to a struct whose first field is the
+ // actual function. So that is what we return as the type of a Go
+ // function.
+
+ Location loc = this->location();
+ Btype* struct_type =
+ gogo->backend()->placeholder_struct_type("__go_descriptor", loc);
+ Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type);
+
std::vector<Backend::Btyped_identifier> fields(1);
fields[0].name = "code";
- fields[0].btype = fntype;
+ fields[0].btype = this->get_backend_fntype(gogo);
fields[0].location = loc;
if (!gogo->backend()->set_placeholder_struct_type(struct_type, fields))
return gogo->backend()->error_type();
@@ -3821,6 +3916,32 @@ Function_type::copy_with_receiver(Type* receiver_type) const
return ret;
}
+// Make a copy of a function type with the receiver as the first
+// parameter.
+
+Function_type*
+Function_type::copy_with_receiver_as_param(bool want_pointer_receiver) const
+{
+ go_assert(this->is_method());
+ Typed_identifier_list* new_params = new Typed_identifier_list();
+ Type* rtype = this->receiver_->type();
+ if (want_pointer_receiver)
+ rtype = Type::make_pointer_type(rtype);
+ Typed_identifier receiver(this->receiver_->name(), rtype,
+ this->receiver_->location());
+ new_params->push_back(receiver);
+ const Typed_identifier_list* orig_params = this->parameters_;
+ if (orig_params != NULL && !orig_params->empty())
+ {
+ for (Typed_identifier_list::const_iterator p = orig_params->begin();
+ p != orig_params->end();
+ ++p)
+ new_params->push_back(*p);
+ }
+ return Type::make_function_type(NULL, new_params, this->results_,
+ this->location_);
+}
+
// Make a copy of a function type ignoring any receiver and adding a
// closure parameter.
@@ -4195,7 +4316,8 @@ Struct_field::is_field_name(const std::string& name) const
// This is a horrible hack caused by the fact that we don't pack
// the names of builtin types. FIXME.
- if (nt != NULL
+ if (!this->is_imported_
+ && nt != NULL
&& nt->is_builtin()
&& nt->name() == Gogo::unpack_hidden_name(name))
return true;
@@ -4204,6 +4326,36 @@ Struct_field::is_field_name(const std::string& name) const
}
}
+// Return whether this field is an unexported field named NAME.
+
+bool
+Struct_field::is_unexported_field_name(Gogo* gogo,
+ const std::string& name) const
+{
+ const std::string& field_name(this->field_name());
+ if (Gogo::is_hidden_name(field_name)
+ && name == Gogo::unpack_hidden_name(field_name)
+ && gogo->pack_hidden_name(name, false) != field_name)
+ return true;
+
+ // Check for the name of a builtin type. This is like the test in
+ // is_field_name, only there we return false if this->is_imported_,
+ // and here we return true.
+ if (this->is_imported_ && this->is_anonymous())
+ {
+ Type* t = this->typed_identifier_.type();
+ if (t->points_to() != NULL)
+ t = t->points_to();
+ Named_type* nt = t->named_type();
+ if (nt != NULL
+ && nt->is_builtin()
+ && nt->name() == Gogo::unpack_hidden_name(name))
+ return true;
+ }
+
+ return false;
+}
+
// Return whether this field is an embedded built-in type.
bool
@@ -4264,12 +4416,7 @@ Struct_type::do_verify()
++p)
{
Type* t = p->type();
- if (t->is_undefined())
- {
- error_at(p->location(), "struct field type is incomplete");
- p->set_type(Type::make_error_type());
- }
- else if (p->is_anonymous())
+ if (p->is_anonymous())
{
if (t->named_type() != NULL && t->points_to() != NULL)
{
@@ -4641,14 +4788,9 @@ Struct_type::is_unexported_local_field(Gogo* gogo,
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf)
- {
- const std::string& field_name(pf->field_name());
- if (Gogo::is_hidden_name(field_name)
- && name == Gogo::unpack_hidden_name(field_name)
- && gogo->pack_hidden_name(name, false) != field_name)
+ if (pf->is_unexported_field_name(gogo, name))
return true;
}
- }
return false;
}
@@ -5250,6 +5392,7 @@ Struct_type::do_import(Import* imp)
Type* ftype = imp->read_type();
Struct_field sf(Typed_identifier(name, ftype, imp->location()));
+ sf.set_is_imported();
if (imp->peek_char() == ' ')
{
@@ -9022,6 +9165,8 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods,
fntype->is_varargs(), location);
gogo->finish_function(fntype->location());
+ if (type->named_type() == NULL && stub->is_function())
+ stub->func_value()->set_is_unnamed_type_stub_method();
if (m->nointerface() && stub->is_function())
stub->func_value()->set_nointerface();
}
@@ -9289,7 +9434,9 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
else
{
bool is_unexported;
- if (!Gogo::is_hidden_name(name))
+ // The test for 'a' and 'z' is to handle builtin names,
+ // which are not hidden.
+ if (!Gogo::is_hidden_name(name) && (name[0] < 'a' || name[0] > 'z'))
is_unexported = false;
else
{
diff --git a/gcc-4.8/gcc/go/gofrontend/types.h b/gcc-4.8/gcc/go/gofrontend/types.h
index d8a3080f5..0c712aaf5 100644
--- a/gcc-4.8/gcc/go/gofrontend/types.h
+++ b/gcc-4.8/gcc/go/gofrontend/types.h
@@ -1138,6 +1138,13 @@ class Type
Function_type* equal_fntype, Named_object** hash_fn,
Named_object** equal_fn);
+ void
+ write_named_hash(Gogo*, Named_type*, Function_type* hash_fntype,
+ Function_type* equal_fntype);
+
+ void
+ write_named_equal(Gogo*, Named_type*);
+
// Build a composite literal for the uncommon type information.
Expression*
uncommon_type_constructor(Gogo*, Type* uncommon_type,
@@ -1717,7 +1724,8 @@ class Function_type : public Type
Typed_identifier_list* results, Location location)
: Type(TYPE_FUNCTION),
receiver_(receiver), parameters_(parameters), results_(results),
- location_(location), is_varargs_(false), is_builtin_(false)
+ location_(location), is_varargs_(false), is_builtin_(false),
+ fnbtype_(NULL)
{ }
// Get the receiver.
@@ -1789,6 +1797,12 @@ class Function_type : public Type
Function_type*
copy_with_receiver(Type*) const;
+ // Return a copy of this type with the receiver treated as the first
+ // parameter. If WANT_POINTER_RECEIVER is true, the receiver is
+ // forced to be a pointer.
+ Function_type*
+ copy_with_receiver_as_param(bool want_pointer_receiver) const;
+
// Return a copy of this type ignoring any receiver and using dummy
// names for all parameters. This is used for thunks for method
// values.
@@ -1798,6 +1812,11 @@ class Function_type : public Type
static Type*
make_function_type_descriptor_type();
+ // Return the backend representation of this function type. This is used
+ // as the real type of a backend function declaration or defintion.
+ Btype*
+ get_backend_fntype(Gogo*);
+
protected:
int
do_traverse(Traverse*);
@@ -1851,6 +1870,9 @@ class Function_type : public Type
// Whether this is a special builtin function which can not simply
// be called. This is used for len, cap, etc.
bool is_builtin_;
+ // The backend representation of this type for backend function
+ // declarations and definitions.
+ Btype* fnbtype_;
};
// The type of a pointer.
@@ -1915,7 +1937,7 @@ class Struct_field
{
public:
explicit Struct_field(const Typed_identifier& typed_identifier)
- : typed_identifier_(typed_identifier), tag_(NULL)
+ : typed_identifier_(typed_identifier), tag_(NULL), is_imported_(false)
{ }
// The field name.
@@ -1926,6 +1948,10 @@ class Struct_field
bool
is_field_name(const std::string& name) const;
+ // Return whether this struct field is an unexported field named NAME.
+ bool
+ is_unexported_field_name(Gogo*, const std::string& name) const;
+
// Return whether this struct field is an embedded built-in type.
bool
is_embedded_builtin(Gogo*) const;
@@ -1963,6 +1989,11 @@ class Struct_field
set_tag(const std::string& tag)
{ this->tag_ = new std::string(tag); }
+ // Record that this field is defined in an imported struct.
+ void
+ set_is_imported()
+ { this->is_imported_ = true; }
+
// Set the type. This is only used in error cases.
void
set_type(Type* type)
@@ -1973,6 +2004,8 @@ class Struct_field
Typed_identifier typed_identifier_;
// The field tag. This is NULL if the field has no tag.
std::string* tag_;
+ // Whether this field is defined in an imported struct.
+ bool is_imported_;
};
// A list of struct fields.