mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
cf5e3504b5
commit
f7191ecdbd
|
@ -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>
|
2013-10-04 Chris Manghane <cmang@google.com>
|
||||||
|
|
||||||
* go-gcc.cc (Backend::convert_expression): New function.
|
* go-gcc.cc (Backend::convert_expression): New function.
|
||||||
|
|
|
@ -334,6 +334,17 @@ class Gcc_backend : public Backend
|
||||||
Bexpression*
|
Bexpression*
|
||||||
label_address(Blabel*, Location);
|
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:
|
private:
|
||||||
// Make a Bexpression from a tree.
|
// Make a Bexpression from a tree.
|
||||||
Bexpression*
|
Bexpression*
|
||||||
|
@ -350,6 +361,10 @@ class Gcc_backend : public Backend
|
||||||
make_type(tree t)
|
make_type(tree t)
|
||||||
{ return new Btype(t); }
|
{ return new Btype(t); }
|
||||||
|
|
||||||
|
Bfunction*
|
||||||
|
make_function(tree t)
|
||||||
|
{ return new Bfunction(t); }
|
||||||
|
|
||||||
Btype*
|
Btype*
|
||||||
fill_in_struct(Btype*, const std::vector<Btyped_identifier>&);
|
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);
|
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.
|
// The single backend.
|
||||||
|
|
||||||
static Gcc_backend gcc_backend;
|
static Gcc_backend gcc_backend;
|
||||||
|
@ -1799,3 +1864,9 @@ var_to_tree(Bvariable* bv)
|
||||||
{
|
{
|
||||||
return bv->get_tree();
|
return bv->get_tree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tree
|
||||||
|
function_to_tree(Bfunction* bf)
|
||||||
|
{
|
||||||
|
return bf->get_tree();
|
||||||
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ class Bexpression;
|
||||||
// The backend representation of a statement.
|
// The backend representation of a statement.
|
||||||
class Bstatement;
|
class Bstatement;
|
||||||
|
|
||||||
// The backend representation of a function definition.
|
// The backend representation of a function definition or declaration.
|
||||||
class Bfunction;
|
class Bfunction;
|
||||||
|
|
||||||
// The backend representation of a block.
|
// The backend representation of a block.
|
||||||
|
@ -498,6 +498,32 @@ class Backend
|
||||||
// recover.
|
// recover.
|
||||||
virtual Bexpression*
|
virtual Bexpression*
|
||||||
label_address(Blabel*, Location) = 0;
|
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.
|
// 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 stat_to_tree(Bstatement*);
|
||||||
extern tree block_to_tree(Bblock*);
|
extern tree block_to_tree(Bblock*);
|
||||||
extern tree var_to_tree(Bvariable*);
|
extern tree var_to_tree(Bvariable*);
|
||||||
|
extern tree function_to_tree(Bfunction*);
|
||||||
|
|
||||||
#endif // !defined(GO_BACKEND_H)
|
#endif // !defined(GO_BACKEND_H)
|
||||||
|
|
|
@ -1240,15 +1240,11 @@ Func_expression::get_code_pointer(Gogo* gogo, Named_object* no, Location loc)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree id = no->get_id(gogo);
|
|
||||||
if (id == error_mark_node)
|
|
||||||
return error_mark_node;
|
|
||||||
|
|
||||||
tree fndecl;
|
tree fndecl;
|
||||||
if (no->is_function())
|
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())
|
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
|
else
|
||||||
go_unreachable();
|
go_unreachable();
|
||||||
|
|
||||||
|
@ -9825,14 +9821,8 @@ Call_expression::do_get_tree(Translate_context* context)
|
||||||
}
|
}
|
||||||
|
|
||||||
tree fntype_tree = type_to_tree(fntype->get_backend(gogo));
|
tree fntype_tree = type_to_tree(fntype->get_backend(gogo));
|
||||||
if (fntype_tree == error_mark_node)
|
tree fnfield_type = type_to_tree(fntype->get_backend_fntype(gogo));
|
||||||
return error_mark_node;
|
if (fntype_tree == error_mark_node || fnfield_type == 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)
|
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
go_assert(FUNCTION_POINTER_TYPE_P(fnfield_type));
|
go_assert(FUNCTION_POINTER_TYPE_P(fnfield_type));
|
||||||
tree rettype = TREE_TYPE(TREE_TYPE(fnfield_type));
|
tree rettype = TREE_TYPE(TREE_TYPE(fnfield_type));
|
||||||
|
|
|
@ -985,74 +985,6 @@ Gogo::write_globals()
|
||||||
delete[] vec;
|
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.
|
// Get a tree for a named object.
|
||||||
|
|
||||||
tree
|
tree
|
||||||
|
@ -1067,11 +999,6 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree name;
|
|
||||||
if (this->classification_ == NAMED_OBJECT_TYPE)
|
|
||||||
name = NULL_TREE;
|
|
||||||
else
|
|
||||||
name = this->get_id(gogo);
|
|
||||||
tree decl;
|
tree decl;
|
||||||
switch (this->classification_)
|
switch (this->classification_)
|
||||||
{
|
{
|
||||||
|
@ -1099,6 +1026,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
|
||||||
decl = error_mark_node;
|
decl = error_mark_node;
|
||||||
else if (INTEGRAL_TYPE_P(TREE_TYPE(expr_tree)))
|
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(),
|
decl = build_decl(named_constant->location().gcc_location(),
|
||||||
CONST_DECL, name, TREE_TYPE(expr_tree));
|
CONST_DECL, name, TREE_TYPE(expr_tree));
|
||||||
DECL_INITIAL(decl) = expr_tree;
|
DECL_INITIAL(decl) = expr_tree;
|
||||||
|
@ -1161,7 +1089,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
|
||||||
case NAMED_OBJECT_FUNC:
|
case NAMED_OBJECT_FUNC:
|
||||||
{
|
{
|
||||||
Function* func = this->u_.func_value;
|
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 (decl != error_mark_node)
|
||||||
{
|
{
|
||||||
if (func->block() != NULL)
|
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.
|
// Get a tree for a function decl.
|
||||||
|
|
||||||
tree
|
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));
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
if (functype != error_mark_node)
|
asm_name = pkgpath;
|
||||||
{
|
asm_name.append(1, '.');
|
||||||
// The type of a function comes back as a pointer to a
|
asm_name.append(Gogo::unpack_hidden_name(no->name()));
|
||||||
// struct whose first field is the function, but we want the
|
if (this->type_->is_method())
|
||||||
// real function type for a function declaration.
|
{
|
||||||
go_assert(POINTER_TYPE_P(functype)
|
asm_name.append(1, '.');
|
||||||
&& TREE_CODE(TREE_TYPE(functype)) == RECORD_TYPE);
|
Type* rtype = this->type_->receiver()->type();
|
||||||
functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype)));
|
asm_name.append(rtype->mangled_name(gogo));
|
||||||
go_assert(FUNCTION_POINTER_TYPE_P(functype));
|
}
|
||||||
functype = TREE_TYPE(functype);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (functype == error_mark_node)
|
// If a function calls the predeclared recover function, we
|
||||||
this->fndecl_ = error_mark_node;
|
// can't inline it, because recover behaves differently in a
|
||||||
else
|
// function passed directly to defer. If this is a recover
|
||||||
{
|
// thunk that we built to test whether a function can be
|
||||||
tree decl = build_decl(this->location().gcc_location(), FUNCTION_DECL,
|
// recovered, we can't inline it, because that will mess up
|
||||||
id, functype);
|
// our return address comparison.
|
||||||
|
bool is_inlinable = !(this->calls_recover_ || this->is_recover_thunk_);
|
||||||
|
|
||||||
this->fndecl_ = decl;
|
// 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_;
|
||||||
|
|
||||||
if (no->package() != NULL)
|
Btype* functype = this->type_->get_backend_fntype(gogo);
|
||||||
;
|
this->fndecl_ =
|
||||||
else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
|
gogo->backend()->function(functype, no->get_id(gogo), asm_name,
|
||||||
;
|
is_visible, false, is_inlinable,
|
||||||
else if (Gogo::unpack_hidden_name(no->name()) == "init"
|
disable_split_stack,
|
||||||
&& !this->type_->is_method())
|
this->in_unique_section_, this->location());
|
||||||
;
|
|
||||||
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_;
|
return function_to_tree(this->fndecl_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a tree for a function declaration.
|
// Get a tree for a function declaration.
|
||||||
|
|
||||||
tree
|
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
|
// Let Go code use an asm declaration to pick up a builtin
|
||||||
// function.
|
// function.
|
||||||
|
@ -1412,56 +1303,44 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
|
||||||
builtin_functions.find(this->asm_name_);
|
builtin_functions.find(this->asm_name_);
|
||||||
if (p != builtin_functions.end())
|
if (p != builtin_functions.end())
|
||||||
{
|
{
|
||||||
this->fndecl_ = p->second;
|
this->fndecl_ = tree_to_function(p->second);
|
||||||
return this->fndecl_;
|
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)
|
Btype* functype = this->fntype_->get_backend_fntype(gogo);
|
||||||
{
|
this->fndecl_ =
|
||||||
// The type of a function comes back as a pointer to a
|
gogo->backend()->function(functype, no->get_id(gogo), asm_name,
|
||||||
// struct whose first field is the function, but we want the
|
true, true, true, false, false,
|
||||||
// real function type for a function declaration.
|
this->location());
|
||||||
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;
|
|
||||||
|
|
||||||
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 function_to_tree(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
|
// 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
|
void
|
||||||
Function::build_tree(Gogo* gogo, Named_object* named_function)
|
Function::build_tree(Gogo* gogo, Named_object* named_function)
|
||||||
{
|
{
|
||||||
tree fndecl = this->fndecl_;
|
tree fndecl = this->get_decl();
|
||||||
go_assert(fndecl != NULL_TREE);
|
go_assert(fndecl != NULL_TREE);
|
||||||
|
|
||||||
tree params = NULL_TREE;
|
tree params = NULL_TREE;
|
||||||
|
@ -1796,7 +1675,7 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
|
||||||
set = NULL_TREE;
|
set = NULL_TREE;
|
||||||
else
|
else
|
||||||
set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
|
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,
|
tree ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR,
|
||||||
void_type_node, set);
|
void_type_node, set);
|
||||||
append_to_statement_list(ret_stmt, &stmt_list);
|
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,
|
retval = this->return_value(gogo, named_function, end_loc,
|
||||||
&stmt_list);
|
&stmt_list);
|
||||||
set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
|
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,
|
ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR,
|
||||||
void_type_node, set);
|
void_type_node, set);
|
||||||
|
|
||||||
|
@ -1869,7 +1748,7 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
|
||||||
*fini = stmt_list;
|
*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
|
// also add statements to STMT_LIST, which need to be executed before
|
||||||
// the assignment. This is used for a return statement with no
|
// the assignment. This is used for a return statement with no
|
||||||
// explicit values.
|
// explicit values.
|
||||||
|
@ -1902,7 +1781,7 @@ Function::return_value(Gogo* gogo, Named_object* named_function,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_));
|
tree rettype = TREE_TYPE(DECL_RESULT(this->get_decl()));
|
||||||
retval = create_tmp_var(rettype, "RESULT");
|
retval = create_tmp_var(rettype, "RESULT");
|
||||||
tree field = TYPE_FIELDS(rettype);
|
tree field = TYPE_FIELDS(rettype);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
@ -2323,15 +2202,11 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
|
||||||
go_assert(m != NULL);
|
go_assert(m != NULL);
|
||||||
|
|
||||||
Named_object* no = m->named_object();
|
Named_object* no = m->named_object();
|
||||||
|
|
||||||
tree fnid = no->get_id(this);
|
|
||||||
|
|
||||||
tree fndecl;
|
tree fndecl;
|
||||||
if (no->is_function())
|
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())
|
else if (no->is_function_declaration())
|
||||||
fndecl = no->func_declaration_value()->get_or_make_decl(this, no,
|
fndecl = no->func_declaration_value()->get_or_make_decl(this, no);
|
||||||
fnid);
|
|
||||||
else
|
else
|
||||||
go_unreachable();
|
go_unreachable();
|
||||||
fndecl = build_fold_addr_expr(fndecl);
|
fndecl = build_fold_addr_expr(fndecl);
|
||||||
|
|
|
@ -5110,6 +5110,75 @@ Named_object::get_backend_variable(Gogo* gogo, Named_object* function)
|
||||||
go_unreachable();
|
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.
|
// Class Bindings.
|
||||||
|
|
||||||
Bindings::Bindings(Bindings* enclosing)
|
Bindings::Bindings(Bindings* enclosing)
|
||||||
|
|
|
@ -48,6 +48,7 @@ class Bstatement;
|
||||||
class Bblock;
|
class Bblock;
|
||||||
class Bvariable;
|
class Bvariable;
|
||||||
class Blabel;
|
class Blabel;
|
||||||
|
class Bfunction;
|
||||||
|
|
||||||
// This file declares the basic classes used to hold the internal
|
// This file declares the basic classes used to hold the internal
|
||||||
// representation of Go which is built by the parser.
|
// representation of Go which is built by the parser.
|
||||||
|
@ -1091,15 +1092,11 @@ class Function
|
||||||
|
|
||||||
// Return the function's decl given an identifier.
|
// Return the function's decl given an identifier.
|
||||||
tree
|
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.
|
// Return the function's decl after it has been built.
|
||||||
tree
|
tree
|
||||||
get_decl() const
|
get_decl() const;
|
||||||
{
|
|
||||||
go_assert(this->fndecl_ != NULL);
|
|
||||||
return this->fndecl_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the function decl to hold a tree of the function code.
|
// Set the function decl to hold a tree of the function code.
|
||||||
void
|
void
|
||||||
|
@ -1170,7 +1167,7 @@ class Function
|
||||||
// The function descriptor, if any.
|
// The function descriptor, if any.
|
||||||
Expression* descriptor_;
|
Expression* descriptor_;
|
||||||
// The function decl.
|
// The function decl.
|
||||||
tree fndecl_;
|
Bfunction* fndecl_;
|
||||||
// The defer stack variable. A pointer to this variable is used to
|
// The defer stack variable. A pointer to this variable is used to
|
||||||
// distinguish the defer stack for one function from another. This
|
// distinguish the defer stack for one function from another. This
|
||||||
// is NULL unless we actually need a defer stack.
|
// 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.
|
// Return a decl for the function given an identifier.
|
||||||
tree
|
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
|
// If there is a descriptor, build it into the backend
|
||||||
// representation.
|
// representation.
|
||||||
|
@ -1290,7 +1287,7 @@ class Function_declaration
|
||||||
// The function descriptor, if any.
|
// The function descriptor, if any.
|
||||||
Expression* descriptor_;
|
Expression* descriptor_;
|
||||||
// The function decl if needed.
|
// The function decl if needed.
|
||||||
tree fndecl_;
|
Bfunction* fndecl_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A variable.
|
// A variable.
|
||||||
|
@ -2181,8 +2178,8 @@ class Named_object
|
||||||
Bvariable*
|
Bvariable*
|
||||||
get_backend_variable(Gogo*, Named_object* function);
|
get_backend_variable(Gogo*, Named_object* function);
|
||||||
|
|
||||||
// Return a tree for the external identifier for this object.
|
// Return the external identifier for this object.
|
||||||
tree
|
std::string
|
||||||
get_id(Gogo*);
|
get_id(Gogo*);
|
||||||
|
|
||||||
// Return a tree representing this object.
|
// Return a tree representing this object.
|
||||||
|
|
|
@ -3382,6 +3382,68 @@ Function_type::do_hash_for_method(Gogo* gogo) const
|
||||||
|
|
||||||
// Get the backend representation for a function type.
|
// 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*
|
Btype*
|
||||||
Function_type::do_get_backend(Gogo* gogo)
|
Function_type::do_get_backend(Gogo* gogo)
|
||||||
{
|
{
|
||||||
|
@ -3395,57 +3457,9 @@ Function_type::do_get_backend(Gogo* gogo)
|
||||||
gogo->backend()->placeholder_struct_type("__go_descriptor", loc);
|
gogo->backend()->placeholder_struct_type("__go_descriptor", loc);
|
||||||
Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type);
|
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);
|
std::vector<Backend::Btyped_identifier> fields(1);
|
||||||
fields[0].name = "code";
|
fields[0].name = "code";
|
||||||
fields[0].btype = fntype;
|
fields[0].btype = this->get_backend_fntype(gogo);
|
||||||
fields[0].location = loc;
|
fields[0].location = loc;
|
||||||
if (!gogo->backend()->set_placeholder_struct_type(struct_type, fields))
|
if (!gogo->backend()->set_placeholder_struct_type(struct_type, fields))
|
||||||
return gogo->backend()->error_type();
|
return gogo->backend()->error_type();
|
||||||
|
|
|
@ -1717,7 +1717,8 @@ class Function_type : public Type
|
||||||
Typed_identifier_list* results, Location location)
|
Typed_identifier_list* results, Location location)
|
||||||
: Type(TYPE_FUNCTION),
|
: Type(TYPE_FUNCTION),
|
||||||
receiver_(receiver), parameters_(parameters), results_(results),
|
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.
|
// Get the receiver.
|
||||||
|
@ -1798,6 +1799,11 @@ class Function_type : public Type
|
||||||
static Type*
|
static Type*
|
||||||
make_function_type_descriptor_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:
|
protected:
|
||||||
int
|
int
|
||||||
do_traverse(Traverse*);
|
do_traverse(Traverse*);
|
||||||
|
@ -1851,6 +1857,9 @@ class Function_type : public Type
|
||||||
// Whether this is a special builtin function which can not simply
|
// Whether this is a special builtin function which can not simply
|
||||||
// be called. This is used for len, cap, etc.
|
// be called. This is used for len, cap, etc.
|
||||||
bool is_builtin_;
|
bool is_builtin_;
|
||||||
|
// The backend representation of this type for backend function
|
||||||
|
// declarations and definitions.
|
||||||
|
Btype* fnbtype_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The type of a pointer.
|
// The type of a pointer.
|
||||||
|
|
Loading…
Reference in New Issue