===================================================================
@@ -3086,6 +3086,11 @@ Gcc_backend::function(Btype* fntype, con
TREE_THIS_VOLATILE(decl) = 1;
if ((flags & function_in_unique_section) != 0)
resolve_unique_section(decl, 0, 1);
+ if ((flags & function_only_inline) != 0)
+ {
+ DECL_EXTERNAL(decl) = 1;
+ DECL_DECLARED_INLINE_P(decl) = 1;
+ }
go_preserve_from_gc(decl);
return new Bfunction(decl);
===================================================================
@@ -1,4 +1,4 @@
-3ecc845c337c15d9a19ed8d277e5ee9eaf49c3ad
+f551ab95f46c3d7bb7c032711e10b03bfa995ee2
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
===================================================================
@@ -726,6 +726,13 @@ class Backend
// possible. This is used for field tracking.
static const unsigned int function_in_unique_section = 1 << 5;
+ // Set if the function should be available for inlining in the
+ // backend, but should not be emitted as a standalone function. Any
+ // call to the function that is not inlined should be treated as a
+ // call to a function defined in a different compilation unit. This
+ // is like a C99 function marked inline but not extern.
+ static const unsigned int function_only_inline = 1 << 6;
+
// 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
===================================================================
@@ -9785,6 +9785,15 @@ Call_expression::do_lower(Gogo* gogo, Na
}
}
+ // If this is a call to an imported function for which we have an
+ // inlinable function body, add it to the list of functions to give
+ // to the backend as inlining opportunities.
+ Func_expression* fe = this->fn_->func_expression();
+ if (fe != NULL
+ && fe->named_object()->is_function_declaration()
+ && fe->named_object()->func_declaration_value()->has_imported_body())
+ gogo->add_imported_inlinable_function(fe->named_object());
+
return this;
}
===================================================================
@@ -97,8 +97,6 @@ go_parse_input_files(const char** filena
}
}
- ::gogo->linemap()->stop();
-
::gogo->clear_file_scope();
// If the global predeclared names are referenced but not defined,
@@ -122,6 +120,10 @@ go_parse_input_files(const char** filena
// form which is easier to use.
::gogo->lower_parse_tree();
+ // At this point we have handled all inline functions, so we no
+ // longer need the linemap.
+ ::gogo->linemap()->stop();
+
// Create function descriptors as needed.
::gogo->create_function_descriptors();
===================================================================
@@ -62,7 +62,9 @@ Gogo::Gogo(Backend* backend, Linemap* li
specific_type_functions_are_written_(false),
named_types_are_converted_(false),
analysis_sets_(),
- gc_roots_()
+ gc_roots_(),
+ imported_inlinable_functions_(),
+ imported_inline_functions_()
{
const Location loc = Linemap::predeclared_location();
@@ -1557,6 +1559,13 @@ Gogo::write_globals()
}
}
+ // Output inline functions, which are in different packages.
+ for (std::vector<Named_object*>::const_iterator p =
+ this->imported_inline_functions_.begin();
+ p != this->imported_inline_functions_.end();
+ ++p)
+ (*p)->get_backend(this, const_decls, type_decls, func_decls);
+
// Register global variables with the garbage collector.
this->register_gc_vars(var_gc, init_stmts, init_bfn);
@@ -2234,6 +2243,20 @@ Gogo::declare_package_function(const std
location);
}
+// Add a function declaration to the list of functions we may want to
+// inline.
+
+void
+Gogo::add_imported_inlinable_function(Named_object* no)
+{
+ go_assert(no->is_function_declaration());
+ Function_declaration* fd = no->func_declaration_value();
+ if (fd->is_on_inlinable_list())
+ return;
+ this->imported_inlinable_functions_.push_back(no);
+ fd->set_is_on_inlinable_list();
+}
+
// Define a type which was already declared.
void
@@ -2881,6 +2904,17 @@ Gogo::lower_parse_tree()
Lower_parse_tree lower_parse_tree(this, NULL);
this->traverse(&lower_parse_tree);
+ // If we found any functions defined in other packages that are
+ // inlinables, import their bodies and turn them into functions.
+ //
+ // Note that as we import inlinable functions we may find more
+ // inlinable functions, so don't use an iterator.
+ for (size_t i = 0; i < this->imported_inlinable_functions_.size(); i++)
+ {
+ Named_object* no = this->imported_inlinable_functions_[i];
+ no->func_declaration_value()->import_function_body(this, no);
+ }
+
// There might be type definitions that involve expressions such as the
// array length. Make sure to lower these expressions as well. Otherwise,
// errors hidden within a type can introduce unexpected errors into later
@@ -5081,7 +5115,8 @@ Function::Function(Function_type* type,
results_are_named_(false), is_unnamed_type_stub_method_(false),
calls_recover_(false), is_recover_thunk_(false), has_recover_thunk_(false),
calls_defer_retaddr_(false), is_type_specific_function_(false),
- in_unique_section_(false), export_for_inlining_(false)
+ in_unique_section_(false), export_for_inlining_(false),
+ is_inline_only_(false)
{
}
@@ -5440,7 +5475,7 @@ Function::export_func(Export* exp, const
block = this->block_;
Function::export_func_with_type(exp, name, this->type_,
this->is_method() && this->nointerface(),
- block);
+ block, this->location_);
}
// Export a function with a type.
@@ -5448,7 +5483,7 @@ Function::export_func(Export* exp, const
void
Function::export_func_with_type(Export* exp, const std::string& name,
const Function_type* fntype, bool nointerface,
- Block* block)
+ Block* block, Location loc)
{
exp->write_c_string("func ");
@@ -5542,12 +5577,15 @@ Function::export_func_with_type(Export*
efb.indent();
efb.write_c_string("// ");
efb.write_string(Linemap::location_to_file(block->start_location()));
+ efb.write_char(':');
+ char buf[100];
+ snprintf(buf, sizeof buf, "%d", Linemap::location_to_line(loc));
+ efb.write_c_string(buf);
efb.write_char('\n');
block->export_block(&efb);
const std::string& body(efb.body());
- char buf[100];
snprintf(buf, sizeof buf, " <inl:%lu>\n",
static_cast<unsigned long>(body.length()));
exp->write_c_string(buf);
@@ -5564,7 +5602,8 @@ Function::import_func(Import* imp, std::
Typed_identifier_list** pparameters,
Typed_identifier_list** presults,
bool* is_varargs,
- bool* nointerface)
+ bool* nointerface,
+ std::string* body)
{
imp->require_c_string("func ");
@@ -5666,6 +5705,7 @@ Function::import_func(Import* imp, std::
{
imp->require_semicolon_if_old_version();
imp->require_c_string("\n");
+ body->clear();
}
else
{
@@ -5694,11 +5734,7 @@ Function::import_func(Import* imp, std::
return;
}
- imp->read(static_cast<size_t>(llen));
-
- // Here we should record the body for later parsing if we see a
- // call to this function. This is not yet implemented. For now
- // we just discard the information.
+ *body = imp->read(static_cast<size_t>(llen));
}
}
@@ -5711,7 +5747,6 @@ Function::get_or_make_decl(Gogo* gogo, N
{
unsigned int flags = 0;
bool is_init_fn = false;
- Type* rtype = NULL;
if (no->package() != NULL)
;
else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
@@ -5735,10 +5770,12 @@ Function::get_or_make_decl(Gogo* gogo, N
{
if (!this->is_unnamed_type_stub_method_)
flags |= Backend::function_is_visible;
- if (this->type_->is_method())
- rtype = this->type_->receiver()->type();
}
+ Type* rtype = NULL;
+ if (this->type_->is_method())
+ rtype = this->type_->receiver()->type();
+
std::string asm_name;
if (!this->asm_name_.empty())
{
@@ -5757,7 +5794,7 @@ Function::get_or_make_decl(Gogo* gogo, N
asm_name = no->name();
}
else
- asm_name = gogo->function_asm_name(no->name(), NULL, rtype);
+ asm_name = gogo->function_asm_name(no->name(), no->package(), rtype);
// If a function calls the predeclared recover function, we
// can't inline it, because recover behaves differently in a
@@ -5803,6 +5840,9 @@ Function::get_or_make_decl(Gogo* gogo, N
|| (this->is_method() && this->nointerface()))
flags |= Backend::function_in_unique_section;
+ if (this->is_inline_only_)
+ flags |= Backend::function_only_inline;
+
Btype* functype = this->type_->get_backend_fntype(gogo);
this->fndecl_ =
gogo->backend()->function(functype, no->get_id(gogo), asm_name,
@@ -6449,6 +6489,108 @@ Block::export_block(Export_function_body
}
}
+// Add exported block data to SET, reading from BODY starting at OFF.
+// Returns whether the import succeeded.
+
+bool
+Block::import_block(Block* set, Import_function_body *ifb, Location loc)
+{
+ Location eloc = ifb->location();
+ Location sloc = loc;
+ const std::string& body(ifb->body());
+ size_t off = ifb->off();
+ while (off < body.length())
+ {
+ int indent = ifb->indent();
+ if (off + indent >= body.length())
+ {
+ go_error_at(eloc,
+ "invalid export data for %qs: insufficient indentation",
+ ifb->name().c_str());
+ return false;
+ }
+ for (int i = 0; i < indent - 1; i++)
+ {
+ if (body[off + i] != ' ')
+ {
+ go_error_at(eloc,
+ "invalid export data for %qs: bad indentation",
+ ifb->name().c_str());
+ return false;
+ }
+ }
+
+ bool at_end = false;
+ if (body[off + indent - 1] == '}')
+ at_end = true;
+ else if (body[off + indent - 1] != ' ')
+ {
+ go_error_at(eloc,
+ "invalid export data for %qs: bad indentation",
+ ifb->name().c_str());
+ return false;
+ }
+
+ off += indent;
+
+ size_t nl = body.find('\n', off);
+ if (nl == std::string::npos)
+ {
+ go_error_at(eloc, "invalid export data for %qs: missing newline",
+ ifb->name().c_str());
+ return false;
+ }
+
+ size_t lineno_pos = body.find(" //", off);
+ if (lineno_pos == std::string::npos || lineno_pos >= nl)
+ {
+ go_error_at(eloc, "invalid export data for %qs: missing line number",
+ ifb->name().c_str());
+ return false;
+ }
+
+ unsigned int lineno = 0;
+ for (size_t i = lineno_pos + 3; i < nl; ++i)
+ {
+ char c = body[i];
+ if (c < '0' || c > '9')
+ {
+ go_error_at(loc,
+ "invalid export data for %qs: invalid line number",
+ ifb->name().c_str());
+ return false;
+ }
+ lineno = lineno * 10 + c - '0';
+ }
+
+ ifb->gogo()->linemap()->start_line(lineno, 1);
+ sloc = ifb->gogo()->linemap()->get_location(0);
+
+ if (at_end)
+ {
+ off = nl + 1;
+ break;
+ }
+
+ ifb->set_off(off);
+ Statement* s = Statement::import_statement(ifb, sloc);
+ if (s == NULL)
+ return false;
+
+ set->add_statement(s);
+
+ size_t at = ifb->off();
+ if (at < nl + 1)
+ off = nl + 1;
+ else
+ off = at;
+ }
+
+ ifb->set_off(off);
+ set->set_end_location(sloc);
+ return true;
+}
+
// Convert a block to the backend representation.
Bblock*
@@ -6607,6 +6749,144 @@ Function_declaration::set_nointerface()
this->pragmas_ |= GOPRAGMA_NOINTERFACE;
}
+// Import an inlinable function. This is used for an inlinable
+// function whose body is recorded in the export data. Parse the
+// export data into a Block and create a regular function using that
+// Block as its body. Redeclare this function declaration as the
+// function.
+
+void
+Function_declaration::import_function_body(Gogo* gogo, Named_object* no)
+{
+ go_assert(no->func_declaration_value() == this);
+ go_assert(no->package() != NULL);
+ const std::string& body(this->imported_body_);
+ go_assert(!body.empty());
+
+ Location orig_loc = no->location();
+
+ // Read the "//FILE:LINE" comment starts the export data.
+
+ size_t indent = 1;
+ if (this->is_method())
+ indent = 2;
+ size_t i = 0;
+ for (; i < indent; i++)
+ {
+ if (body.at(i) != ' ')
+ {
+ go_error_at(this->location_,
+ "invalid export body for %qs: bad initial indentation",
+ no->message_name().c_str());
+ return;
+ }
+ }
+
+ if (body.substr(i, 2) != "//")
+ {
+ go_error_at(this->location_,
+ "invalid export body for %qs: missing file comment",
+ no->message_name().c_str());
+ return;
+ }
+
+ size_t colon = body.find(':', i + 2);
+ size_t nl = body.find('\n', i + 2);
+ if (nl == std::string::npos)
+ {
+ go_error_at(this->location_,
+ "invalid export body for %qs: missing file name",
+ no->message_name().c_str());
+ return;
+ }
+ if (colon == std::string::npos || nl < colon)
+ {
+ go_error_at(this->location_,
+ "invalid export body for %qs: missing initial line number",
+ no->message_name().c_str());
+ return;
+ }
+
+ std::string file = body.substr(i + 2, colon - (i + 2));
+ std::string linestr = body.substr(colon + 1, nl - (colon + 1));
+ char* end;
+ long linenol = strtol(linestr.c_str(), &end, 10);
+ if (*end != '\0')
+ {
+ go_error_at(this->location_,
+ "invalid export body for %qs: invalid initial line number",
+ no->message_name().c_str());
+ return;
+ }
+ unsigned int lineno = static_cast<unsigned int>(linenol);
+
+ // Turn the file/line into a location.
+
+ char* alc = new char[file.length() + 1];
+ memcpy(alc, file.data(), file.length());
+ alc[file.length()] = '\0';
+ gogo->linemap()->start_file(alc, lineno);
+ gogo->linemap()->start_line(lineno, 1);
+ Location start_loc = gogo->linemap()->get_location(0);
+
+ // Define the function with an outer block that declares the
+ // parameters.
+
+ Function_type* fntype = this->fntype_;
+
+ Block* outer = new Block(NULL, start_loc);
+
+ Function* fn = new Function(fntype, NULL, outer, start_loc);
+ fn->set_is_inline_only();
+
+ if (fntype->is_method())
+ {
+ const Typed_identifier* receiver = fntype->receiver();
+ Variable* recv_param = new Variable(receiver->type(), NULL, false,
+ true, true, start_loc);
+ outer->bindings()->add_variable(receiver->name(), NULL, recv_param);
+ }
+
+ const Typed_identifier_list* params = fntype->parameters();
+ bool is_varargs = fntype->is_varargs();
+ if (params != NULL)
+ {
+ for (Typed_identifier_list::const_iterator p = params->begin();
+ p != params->end();
+ ++p)
+ {
+ Variable* param = new Variable(p->type(), NULL, false, true, false,
+ start_loc);
+ if (is_varargs && p + 1 == params->end())
+ param->set_is_varargs_parameter();
+ outer->bindings()->add_variable(p->name(), NULL, param);
+ }
+ }
+
+ fn->create_result_variables(gogo);
+
+ if (!fntype->is_method())
+ {
+ const Package* package = no->package();
+ no = package->bindings()->add_function(no->name(), package, fn);
+ }
+ else
+ {
+ Named_type* rtype = fntype->receiver()->type()->deref()->named_type();
+ go_assert(rtype != NULL);
+ no = rtype->add_method(no->name(), fn);
+ }
+
+ Import_function_body ifb(gogo, orig_loc, no, body, nl + 1, outer, indent);
+
+ if (!Block::import_block(outer, &ifb, start_loc))
+ return;
+
+ gogo->lower_block(no, outer);
+
+ gogo->add_imported_inline_function(no);
+}
+
// Return the function descriptor.
Expression*
@@ -8121,14 +8401,21 @@ Bindings::new_definition(Named_object* o
{
// We declare the hash and equality functions before defining
// them, because we sometimes see that we need the declaration
- // while we are in the middle of a different function. We
- // declare the main function before the user defines it, to
+ // while we are in the middle of a different function.
+ //
+ // We declare the main function before the user defines it, to
// give better error messages.
+ //
+ // We declare inline functions before we define them, as we
+ // only define them if we need them.
if (new_object->is_function()
&& ((Linemap::is_predeclared_location(old_object->location())
&& Linemap::is_predeclared_location(new_object->location()))
|| (Gogo::unpack_hidden_name(old_object->name()) == "main"
- && Linemap::is_unknown_location(old_object->location()))))
+ && Linemap::is_unknown_location(old_object->location()))
+ || (new_object->package() != NULL
+ && old_object->func_declaration_value()->has_imported_body()
+ && new_object->func_value()->is_inline_only())))
{
Function_type* old_type =
old_object->func_declaration_value()->type();
===================================================================
@@ -43,6 +43,7 @@ class Backend;
class Export;
class Export_function_body;
class Import;
+class Import_function_body;
class Bexpression;
class Btype;
class Bstatement;
@@ -420,6 +421,17 @@ class Gogo
Named_object*
declare_package_function(const std::string&, Function_type*, Location);
+ // Add a function declaration to the list of functions we may want
+ // to inline.
+ void
+ add_imported_inlinable_function(Named_object*);
+
+ // Add a function to the list of functions that we do want to
+ // inline.
+ void
+ add_imported_inline_function(Named_object* no)
+ { this->imported_inline_functions_.push_back(no); }
+
// Add a label.
Label*
add_label_definition(const std::string&, Location);
@@ -661,7 +673,7 @@ class Gogo
propagate_escape(Escape_context*, Node*);
// Add notes about the escape level of a function's input and output
- // parameters for exporting and importing top level functions.
+ // parameters for exporting and importing top level functions.
void
tag_function(Escape_context*, Named_object*);
@@ -726,7 +738,7 @@ class Gogo
void
simplify_thunk_statements();
- // Dump AST if -fgo-dump-ast is set
+ // Dump AST if -fgo-dump-ast is set.
void
dump_ast(const char* basename);
@@ -1062,6 +1074,12 @@ class Gogo
std::vector<Analysis_set> analysis_sets_;
// A list of objects to add to the GC roots.
std::vector<Expression*> gc_roots_;
+ // A list of function declarations with imported bodies that we may
+ // want to inline.
+ std::vector<Named_object*> imported_inlinable_functions_;
+ // A list of functions that we want to inline. These will be sent
+ // to the backend.
+ std::vector<Named_object*> imported_inline_functions_;
};
// A block of statements.
@@ -1144,6 +1162,10 @@ class Block
void
export_block(Export_function_body*);
+ // Turn exported block data into a block.
+ static bool
+ import_block(Block*, Import_function_body*, Location);
+
// Convert the block to the backend representation.
Bblock*
get_backend(Translate_context*);
@@ -1419,6 +1441,17 @@ class Function
set_export_for_inlining()
{ this->export_for_inlining_ = true; }
+ // Return whether this function is inline only.
+ bool
+ is_inline_only() const
+ { return this->is_inline_only_; }
+
+ // Mark the function as inline only: the body should not be emitted
+ // if it is not inlined.
+ void
+ set_is_inline_only()
+ { this->is_inline_only_ = true; }
+
// Swap with another function. Used only for the thunk which calls
// recover.
void
@@ -1476,14 +1509,15 @@ class Function
// Export a function with a type.
static void
export_func_with_type(Export*, const std::string& name,
- const Function_type*, bool nointerface, Block* block);
+ const Function_type*, bool nointerface, Block* block,
+ Location);
// Import a function.
static void
import_func(Import*, std::string* pname, Typed_identifier** receiver,
Typed_identifier_list** pparameters,
Typed_identifier_list** presults, bool* is_varargs,
- bool* nointerface);
+ bool* nointerface, std::string* body);
private:
// Type for mapping from label names to Label objects.
@@ -1557,6 +1591,9 @@ class Function
// True if we should export the body of this function for
// cross-package inlining.
bool export_for_inlining_ : 1;
+ // True if this function is inline only: if it should not be emitted
+ // if it is not inlined.
+ bool is_inline_only_ : 1;
};
// A snapshot of the current binding state.
@@ -1600,7 +1637,8 @@ class Function_declaration
public:
Function_declaration(Function_type* fntype, Location location)
: fntype_(fntype), location_(location), asm_name_(), descriptor_(NULL),
- fndecl_(NULL), pragmas_(0)
+ fndecl_(NULL), pragmas_(0), imported_body_(),
+ is_on_inlinable_list_(false)
{ }
Function_type*
@@ -1646,6 +1684,30 @@ class Function_declaration
void
set_nointerface();
+ // Whether we have an imported function body.
+ bool
+ has_imported_body() const
+ { return !this->imported_body_.empty(); }
+
+ // Record the imported body of this function.
+ void
+ set_imported_body(const std::string& imported_body)
+ { this->imported_body_ = imported_body; }
+
+ // Whether this declaration is on the list of inlinable functions.
+ bool
+ is_on_inlinable_list() const
+ { return this->is_on_inlinable_list_; }
+
+ // Set that this function is on the list of inlinable functions.
+ void
+ set_is_on_inlinable_list()
+ { this->is_on_inlinable_list_ = true; }
+
+ // Import the function body, creating a function.
+ void
+ import_function_body(Gogo*, Named_object*);
+
// Return an expression for the function descriptor, given the named
// object for this function. This may only be called for functions
// without a closure. This will be an immutable struct with one
@@ -1673,7 +1735,7 @@ class Function_declaration
{
Function::export_func_with_type(exp, name, this->fntype_,
this->is_method() && this->nointerface(),
- NULL);
+ NULL, this->location_);
}
// Check that the types used in this declaration's signature are defined.
@@ -1694,6 +1756,10 @@ class Function_declaration
Bfunction* fndecl_;
// Pragmas for this function. This is a set of GOPRAGMA bits.
unsigned int pragmas_;
+ // Export data for function body if imported from a different package.
+ std::string imported_body_;
+ // Whether this declaration is already on the list of inlinable functions.
+ bool is_on_inlinable_list_;
};
// A variable.
@@ -1789,7 +1855,7 @@ class Variable
bool
is_in_heap() const
{
- return this->is_address_taken_
+ return this->is_address_taken_
&& this->escapes_
&& !this->is_global_;
}
@@ -2103,7 +2169,7 @@ class Result_variable
void
set_non_escaping_address_taken()
{ this->is_non_escaping_address_taken_ = true; }
-
+
// Return whether this variable escapes the function it is declared in.
bool
escapes()
@@ -3200,7 +3266,7 @@ class Package
// Return the bindings.
Bindings*
- bindings()
+ bindings() const
{ return this->bindings_; }
// Type used to map import names to package aliases.
===================================================================
@@ -744,8 +744,9 @@ Import::import_func(Package* package)
Typed_identifier_list* results;
bool is_varargs;
bool nointerface;
- Function::import_func(this, &name, &receiver,
- ¶meters, &results, &is_varargs, &nointerface);
+ std::string body;
+ Function::import_func(this, &name, &receiver, ¶meters, &results,
+ &is_varargs, &nointerface, &body);
Function_type *fntype = Type::make_function_type(receiver, parameters,
results, this->location_);
if (is_varargs)
@@ -788,6 +789,8 @@ Import::import_func(Package* package)
if (nointerface)
no->func_declaration_value()->set_nointerface();
+ if (!body.empty() && !no->func_declaration_value()->has_imported_body())
+ no->func_declaration_value()->set_imported_body(body);
return no;
}
@@ -1395,3 +1398,13 @@ Stream_from_file::do_advance(size_t skip
this->data_.clear();
}
}
+
+// Class Import_function_body.
+
+// The name of the function we are parsing.
+
+const std::string&
+Import_function_body::name() const
+{
+ return this->named_object_->name();
+}
===================================================================
@@ -11,6 +11,7 @@
#include "go-linemap.h"
class Gogo;
+class Block;
class Package;
class Type;
class Named_object;
@@ -464,4 +465,74 @@ class Stream_from_string_ref : public Im
size_t end_;
};
+// Class to manage importing a function body. This is passed around
+// to Statements and Expressions. It parses the function into the IR.
+
+class Import_function_body
+{
+ public:
+ Import_function_body(Gogo* gogo, Location loc, Named_object* named_object,
+ const std::string& body, size_t off, Block* block,
+ int indent)
+ : gogo_(gogo), loc_(loc), named_object_(named_object), body_(body),
+ off_(off), block_(block), indent_(indent)
+ { }
+
+ // The IR.
+ Gogo*
+ gogo()
+ { return this->gogo_; }
+
+ // The location to report in an error message.
+ Location
+ location() const
+ { return this->loc_; }
+
+ // A reference to the body we are reading.
+ const std::string&
+ body() const
+ { return this->body_; }
+
+ // The current offset into the body.
+ size_t
+ off()
+ { return this->off_; }
+
+ // Update the offset into the body.
+ void
+ set_off(size_t off)
+ { this->off_ = off; }
+
+ // The current block.
+ Block*
+ block()
+ { return this->block_; }
+
+ // The current indentation.
+ int
+ indent() const
+ { return this->indent_; }
+
+ // The name of the function we are parsing.
+ const std::string&
+ name() const;
+
+ private:
+ // The IR.
+ Gogo* gogo_;
+ // The location to report in an error message.
+ Location loc_;
+ // The function we are parsing.
+ Named_object* named_object_;
+ // The exported data we are parsing. Note that this is a reference;
+ // the body string must laster longer than this object.
+ const std::string& body_;
+ // The current offset into body_.
+ size_t off_;
+ // Current block.
+ Block* block_;
+ // Current expected indentation level.
+ int indent_;
+};
+
#endif // !defined(GO_IMPORT_H)
===================================================================
@@ -121,6 +121,14 @@ Statement::determine_types()
this->do_determine_types();
}
+// Read a statement from export data.
+
+Statement*
+Statement::import_statement(Import_function_body*, Location)
+{
+ go_unreachable();
+}
+
// If this is a thunk statement, return it.
Thunk_statement*
===================================================================
@@ -338,6 +338,10 @@ class Statement
export_statement(Export_function_body* efb)
{ this->do_export_statement(efb); }
+ // Read a statement from export data.
+ static Statement*
+ import_statement(Import_function_body*, Location);
+
// Return whether this is a block statement.
bool
is_block_statement() const
===================================================================
@@ -9865,7 +9865,9 @@ Named_type::add_method(const std::string
go_assert(!this->is_alias_);
if (this->local_methods_ == NULL)
this->local_methods_ = new Bindings(NULL);
- return this->local_methods_->add_function(name, NULL, function);
+ return this->local_methods_->add_function(name,
+ this->named_object_->package(),
+ function);
}
// Add a method declaration to this type.