aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorChris Manghane <cmang@google.com>2013-10-11 03:15:33 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2013-10-11 03:15:33 +0000
commitf7191ecdbd3adad32b561db40fac6978df6409fe (patch)
tree5f41fdf78ab663a67c63db5beabf5b7175f799ba /gcc/go
parentcf5e3504b55071f73420c3ab7756200b1dad7b7a (diff)
downloadgcc-f7191ecdbd3adad32b561db40fac6978df6409fe.zip
gcc-f7191ecdbd3adad32b561db40fac6978df6409fe.tar.gz
gcc-f7191ecdbd3adad32b561db40fac6978df6409fe.tar.bz2
compiler: Use backend interface for function declarations.
* go-gcc.cc (Backend::error_function): New function. (Backend::function): New function. (Backend::make_function): New function. (function_to_tree): New function. From-SVN: r203403
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/ChangeLog7
-rw-r--r--gcc/go/go-gcc.cc71
-rw-r--r--gcc/go/gofrontend/backend.h29
-rw-r--r--gcc/go/gofrontend/expressions.cc18
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc341
-rw-r--r--gcc/go/gofrontend/gogo.cc69
-rw-r--r--gcc/go/gofrontend/gogo.h19
-rw-r--r--gcc/go/gofrontend/types.cc112
-rw-r--r--gcc/go/gofrontend/types.h11
9 files changed, 368 insertions, 309 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index eddf393..6d6217b 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,10 @@
+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-04 Chris Manghane <cmang@google.com>
* go-gcc.cc (Backend::convert_expression): New function.
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index fcfd41b..6b77d94 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -334,6 +334,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 +361,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>&);
@@ -1724,6 +1739,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 +1864,9 @@ var_to_tree(Bvariable* bv)
{
return bv->get_tree();
}
+
+tree
+function_to_tree(Bfunction* bf)
+{
+ return bf->get_tree();
+}
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index fa3e3cc..e73c98c 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/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.
@@ -498,6 +498,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 +543,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/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 0647a50..37f8822 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -1240,15 +1240,11 @@ Func_expression::get_code_pointer(Gogo* gogo, Named_object* no, Location loc)
return error_mark_node;
}
- tree id = no->get_id(gogo);
- if (id == error_mark_node)
- return error_mark_node;
-
tree fndecl;
if (no->is_function())
- fndecl = no->func_value()->get_or_make_decl(gogo, no, id);
+ 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();
@@ -9825,14 +9821,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));
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index a95f290..78a8c6a 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/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 = func->get_or_make_decl(gogo, this);
if (decl != error_mark_node)
{
if (func->block() != NULL)
@@ -1289,120 +1217,83 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
// Get a tree for a function decl.
tree
-Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
+Function::get_or_make_decl(Gogo* gogo, Named_object* no)
{
- if (this->fndecl_ == NULL_TREE)
+ if (this->fndecl_ == NULL)
{
- 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);
+ 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())
+ {
+ 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));
+ }
+ }
- go_preserve_from_gc(decl);
- }
+ // 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_;
+ return function_to_tree(this->fndecl_);
}
// Get a tree for a function declaration.
tree
-Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
+Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no)
{
- if (this->fndecl_ == NULL_TREE)
+ if (this->fndecl_ == NULL)
{
// Let Go code use an asm declaration to pick up a builtin
// function.
@@ -1412,56 +1303,44 @@ 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;
- return this->fndecl_;
+ this->fndecl_ = tree_to_function(p->second);
+ return p->second;
}
}
- tree functype = type_to_tree(this->fntype_->get_backend(gogo));
+ std::string asm_name;
+ if (this->asm_name_.empty())
+ {
+ asm_name = (no->package() == NULL
+ ? gogo->pkgpath_symbol()
+ : no->package()->pkgpath_symbol());
+ asm_name.append(1, '.');
+ asm_name.append(Gogo::unpack_hidden_name(no->name()));
+ if (this->fntype_->is_method())
+ {
+ asm_name.append(1, '.');
+ Type* rtype = this->fntype_->receiver()->type();
+ asm_name.append(rtype->mangled_name(gogo));
+ }
+ }
- 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);
- }
+ 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());
+ }
- 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;
+ return function_to_tree(this->fndecl_);
+}
- if (this->asm_name_.empty())
- {
- std::string asm_name = (no->package() == NULL
- ? gogo->pkgpath_symbol()
- : no->package()->pkgpath_symbol());
- asm_name.append(1, '.');
- asm_name.append(Gogo::unpack_hidden_name(no->name()));
- if (this->fntype_->is_method())
- {
- asm_name.append(1, '.');
- Type* rtype = this->fntype_->receiver()->type();
- asm_name.append(rtype->mangled_name(gogo));
- }
- SET_DECL_ASSEMBLER_NAME(decl,
- get_identifier_from_string(asm_name));
- }
- }
- this->fndecl_ = decl;
- go_preserve_from_gc(decl);
- }
- return this->fndecl_;
+// 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
@@ -1558,7 +1437,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 +1675,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 +1730,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 +1748,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 +1781,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,15 +2202,11 @@ 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;
if (no->is_function())
- fndecl = no->func_value()->get_or_make_decl(this, no, fnid);
+ fndecl = 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);
+ fndecl = no->func_declaration_value()->get_or_make_decl(this, no);
else
go_unreachable();
fndecl = build_fold_addr_expr(fndecl);
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 9f918cb..a8f7754 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -5110,6 +5110,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/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 23968d4a..5b416b0 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/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.
@@ -1091,15 +1092,11 @@ class Function
// Return the function's decl given an identifier.
tree
- get_or_make_decl(Gogo*, Named_object*, tree id);
+ 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 +1167,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.
@@ -1267,7 +1264,7 @@ class Function_declaration
// Return a decl for the function given an identifier.
tree
- get_or_make_decl(Gogo*, Named_object*, tree id);
+ get_or_make_decl(Gogo*, Named_object*);
// If there is a descriptor, build it into the backend
// representation.
@@ -1290,7 +1287,7 @@ class Function_declaration
// The function descriptor, if any.
Expression* descriptor_;
// The function decl if needed.
- tree fndecl_;
+ Bfunction* fndecl_;
};
// A variable.
@@ -2181,8 +2178,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/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 7fa84c5..f73ca7a 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -3383,6 +3383,68 @@ Function_type::do_hash_for_method(Gogo* gogo) const
// Get the backend representation for a function type.
Btype*
+Function_type::get_backend_fntype(Gogo* gogo)
+{
+ if (this->fnbtype_ == NULL)
+ {
+ Backend::Btyped_identifier breceiver;
+ if (this->receiver_ != NULL)
+ {
+ breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name());
+
+ // We always pass the address of the receiver parameter, in
+ // order to make interface calls work with unknown types.
+ Type* rtype = this->receiver_->type();
+ if (rtype->points_to() == NULL)
+ rtype = Type::make_pointer_type(rtype);
+ breceiver.btype = rtype->get_backend(gogo);
+ breceiver.location = this->receiver_->location();
+ }
+
+ std::vector<Backend::Btyped_identifier> bparameters;
+ if (this->parameters_ != NULL)
+ {
+ bparameters.resize(this->parameters_->size());
+ size_t i = 0;
+ for (Typed_identifier_list::const_iterator p =
+ this->parameters_->begin(); p != this->parameters_->end();
+ ++p, ++i)
+ {
+ bparameters[i].name = Gogo::unpack_hidden_name(p->name());
+ bparameters[i].btype = p->type()->get_backend(gogo);
+ bparameters[i].location = p->location();
+ }
+ go_assert(i == bparameters.size());
+ }
+
+ std::vector<Backend::Btyped_identifier> bresults;
+ if (this->results_ != NULL)
+ {
+ bresults.resize(this->results_->size());
+ size_t i = 0;
+ for (Typed_identifier_list::const_iterator p =
+ this->results_->begin(); p != this->results_->end();
+ ++p, ++i)
+ {
+ bresults[i].name = Gogo::unpack_hidden_name(p->name());
+ bresults[i].btype = p->type()->get_backend(gogo);
+ bresults[i].location = p->location();
+ }
+ go_assert(i == bresults.size());
+ }
+
+ 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
@@ -3395,57 +3457,9 @@ Function_type::do_get_backend(Gogo* gogo)
gogo->backend()->placeholder_struct_type("__go_descriptor", loc);
Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type);
- Backend::Btyped_identifier breceiver;
- if (this->receiver_ != NULL)
- {
- breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name());
-
- // We always pass the address of the receiver parameter, in
- // order to make interface calls work with unknown types.
- Type* rtype = this->receiver_->type();
- if (rtype->points_to() == NULL)
- rtype = Type::make_pointer_type(rtype);
- breceiver.btype = rtype->get_backend(gogo);
- breceiver.location = this->receiver_->location();
- }
-
- std::vector<Backend::Btyped_identifier> bparameters;
- if (this->parameters_ != NULL)
- {
- bparameters.resize(this->parameters_->size());
- size_t i = 0;
- for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
- p != this->parameters_->end();
- ++p, ++i)
- {
- bparameters[i].name = Gogo::unpack_hidden_name(p->name());
- bparameters[i].btype = p->type()->get_backend(gogo);
- bparameters[i].location = p->location();
- }
- go_assert(i == bparameters.size());
- }
-
- std::vector<Backend::Btyped_identifier> bresults;
- if (this->results_ != NULL)
- {
- bresults.resize(this->results_->size());
- size_t i = 0;
- for (Typed_identifier_list::const_iterator p = this->results_->begin();
- p != this->results_->end();
- ++p, ++i)
- {
- bresults[i].name = Gogo::unpack_hidden_name(p->name());
- bresults[i].btype = p->type()->get_backend(gogo);
- bresults[i].location = p->location();
- }
- go_assert(i == bresults.size());
- }
-
- Btype* fntype = gogo->backend()->function_type(breceiver, bparameters,
- bresults, loc);
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();
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index d8a3080..928c593 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -1717,7 +1717,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.
@@ -1798,6 +1799,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 +1857,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.