diff options
-rw-r--r-- | gcc/go/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 5 | ||||
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/backend.h | 7 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 9 | ||||
-rw-r--r-- | gcc/go/gofrontend/go.cc | 6 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 323 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 84 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.cc | 17 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.h | 71 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 8 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 4 |
13 files changed, 512 insertions, 33 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 5f18b80..01781ed 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,8 @@ +2018-11-27 Ian Lance Taylor <iant@golang.org> + + * go-gcc.cc (Gcc_backend::function): Handle function_only_inline + flag. + 2018-11-13 David Malcolm <dmalcolm@redhat.com> * go-gcc-diagnostics.cc: Replace "source_location" with "location_t". diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index be23029..32b91c1 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -3086,6 +3086,11 @@ Gcc_backend::function(Btype* fntype, const std::string& name, 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); diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index d68d123..df34439 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index d2e93d2..6bca42e 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -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 diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 75fa19b..db7c981 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -9785,6 +9785,15 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, } } + // 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; } diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc index d444e4a..d8da232 100644 --- a/gcc/go/gofrontend/go.cc +++ b/gcc/go/gofrontend/go.cc @@ -97,8 +97,6 @@ go_parse_input_files(const char** filenames, unsigned int filename_count, } } - ::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** filenames, unsigned int filename_count, // 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(); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 354eaba..552de18 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -62,7 +62,9 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size) 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::string& name, Function_type* type, 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, Named_object* enclosing, Block* block, 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 std::string& name) 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 std::string& name) 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* exp, const std::string& name, 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::string* pname, 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::string* pname, { imp->require_semicolon_if_old_version(); imp->require_c_string("\n"); + body->clear(); } else { @@ -5694,11 +5734,7 @@ Function::import_func(Import* imp, std::string* pname, 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, Named_object* no) { 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, Named_object* no) { 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, Named_object* no) 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, Named_object* no) || (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* efb) } } +// 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* old_object, Named_object* new_object) { // 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(); diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 1b13e5c..1c79f6f 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -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. diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index a0a1f18..7ee3cb6 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -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(); +} diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h index 9c6cbfe..3fc05df 100644 --- a/gcc/go/gofrontend/import.h +++ b/gcc/go/gofrontend/import.h @@ -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 Import::Stream 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) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 718139c..60b7a70 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -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* diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index ff57a21..eef8646 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -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 diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 2d348ba..2750242 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -9865,7 +9865,9 @@ Named_type::add_method(const std::string& name, Function* function) 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. |