diff options
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/export.cc | 163 | ||||
-rw-r--r-- | gcc/go/gofrontend/export.h | 11 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 91 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 10 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 102 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 43 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.cc | 97 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.h | 50 |
9 files changed, 482 insertions, 87 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index b1b36b2a..43df2f7 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -95784e8eec75cfeb2363fb22b51085380e564af9 +37a47e4691b4602dd167f82c64a6569019584a80 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/export.cc b/gcc/go/gofrontend/export.cc index 066455a..108fdac 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -11,6 +11,7 @@ #include "gogo.h" #include "types.h" +#include "expressions.h" #include "statements.h" #include "export.h" @@ -89,13 +90,88 @@ typedef Unordered_map_hash(const Type*, int, Type_hash_alias_identical, static Type_refs type_refs; +// A traversal class to collect functions and global variables +// referenced by inlined functions. + +class Collect_references_from_inline : public Traverse +{ + public: + Collect_references_from_inline(Unordered_set(Named_object*)* exports, + std::vector<Named_object*>* check_inline_refs) + : Traverse(traverse_expressions), + exports_(exports), check_inline_refs_(check_inline_refs) + { } + + int + expression(Expression**); + + private: + // The set of named objects to export. + Unordered_set(Named_object*)* exports_; + // Functions we are exporting with inline bodies that need to be checked. + std::vector<Named_object*>* check_inline_refs_; +}; + +int +Collect_references_from_inline::expression(Expression** pexpr) +{ + const Expression* expr = *pexpr; + + const Var_expression* ve = expr->var_expression(); + if (ve != NULL) + { + Named_object* no = ve->named_object(); + if (no->is_variable() && no->var_value()->is_global()) + { + this->exports_->insert(no); + no->var_value()->set_is_referenced_by_inline(); + } + return TRAVERSE_CONTINUE; + } + + const Func_expression* fe = expr->func_expression(); + if (fe != NULL) + { + Named_object* no = fe->named_object(); + std::pair<Unordered_set(Named_object*)::iterator, bool> ins = + this->exports_->insert(no); + + if (no->is_function()) + no->func_value()->set_is_referenced_by_inline(); + + // If ins.second is false then this object was already in + // exports_, in which case it was already added to + // check_inline_refs_ the first time we added it to exports_, so + // we don't need to add it again. + if (ins.second + && no->is_function() + && no->func_value()->export_for_inlining()) + this->check_inline_refs_->push_back(no); + + return TRAVERSE_CONTINUE; + } + + return TRAVERSE_CONTINUE; +} + // A functor to sort Named_object pointers by name. struct Sort_bindings { bool operator()(const Named_object* n1, const Named_object* n2) const - { return n1->name() < n2->name(); } + { + if (n1->package() != n2->package()) + { + if (n1->package() == NULL) + return true; + if (n2->package() == NULL) + return false; + return n1->package()->pkgpath() < n2->package()->pkgpath(); + } + + return n1->name() < n2->name(); + } }; // Return true if we should export NO. @@ -153,17 +229,26 @@ Export::export_globals(const std::string& package_name, if (saw_errors()) return; - // Export the symbols in sorted order. That will reduce cases where - // irrelevant changes to the source code affect the exported - // interface. - std::vector<Named_object*> exports; - exports.reserve(bindings->size_definitions()); + // EXPORTS is the set of objects to export. CHECK_INLINE_REFS is a + // list of exported function with inline bodies that need to be + // checked for references to other objects. Every function on + // CHECK_INLINE_REFS is also on EXPORTS. + Unordered_set(Named_object*) exports; + std::vector<Named_object*> check_inline_refs; for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); p != bindings->end_definitions(); ++p) - if (should_export(*p)) - exports.push_back(*p); + { + if (should_export(*p)) + { + exports.insert(*p); + + if ((*p)->is_function() + && (*p)->func_value()->export_for_inlining()) + check_inline_refs.push_back(*p); + } + } for (Bindings::const_declarations_iterator p = bindings->begin_declarations(); @@ -174,15 +259,47 @@ Export::export_globals(const std::string& package_name, // supporting C code. We do not export type declarations. if (p->second->is_function_declaration() && should_export(p->second)) - exports.push_back(p->second); + exports.insert(p->second); + } + + // Look through the bodies of the functions in CHECK_INLINE_REFS to + // find other names we may need to export, to satisfy those + // references. Use CHECKED to skip checking function bodies more + // than once. + Unordered_set(Named_object*) checked; + Collect_references_from_inline refs(&exports, &check_inline_refs); + while (!check_inline_refs.empty()) + { + Named_object* no = check_inline_refs.back(); + check_inline_refs.pop_back(); + std::pair<Unordered_set(Named_object*)::iterator, bool> ins = + checked.insert(no); + if (ins.second) + { + // This traversal may add new objects to EXPORTS and new + // functions to CHECK_INLINE_REFS. + no->func_value()->block()->traverse(&refs); + } } - std::sort(exports.begin(), exports.end(), Sort_bindings()); + // Export the symbols in sorted order. That will reduce cases where + // irrelevant changes to the source code affect the exported + // interface. + std::vector<Named_object*> sorted_exports; + sorted_exports.reserve(exports.size()); + + for (Unordered_set(Named_object*)::const_iterator p = exports.begin(); + p != exports.end(); + ++p) + sorted_exports.push_back(*p); + + std::sort(sorted_exports.begin(), sorted_exports.end(), Sort_bindings()); // Assign indexes to all exported types and types referenced by // exported types, and collect all packages mentioned. Unordered_set(const Package*) type_imports; - int unexported_type_index = this->prepare_types(&exports, &type_imports); + int unexported_type_index = this->prepare_types(&sorted_exports, + &type_imports); // Although the export data is readable, at least this version is, // it is conceptually a binary format. Start with a four byte @@ -223,8 +340,8 @@ Export::export_globals(const std::string& package_name, this->write_types(unexported_type_index); // Write out the non-type export data. - for (std::vector<Named_object*>::const_iterator p = exports.begin(); - p != exports.end(); + for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin(); + p != sorted_exports.end(); ++p) { if (!(*p)->is_type()) @@ -591,6 +708,7 @@ Export::write_imports(const std::map<std::string, Package*>& imports, std::sort(sorted_imports.begin(), sorted_imports.end(), import_compare); + int package_index = 1; for (std::vector<std::pair<std::string, Package*> >::const_iterator p = sorted_imports.begin(); p != sorted_imports.end(); @@ -604,7 +722,8 @@ Export::write_imports(const std::map<std::string, Package*>& imports, this->write_string(p->first); this->write_c_string("\"\n"); - this->packages_.insert(p->second); + this->packages_[p->second] = package_index; + package_index++; } // Write out a separate list of indirectly imported packages. @@ -631,6 +750,9 @@ Export::write_imports(const std::map<std::string, Package*>& imports, this->write_c_string(" "); this->write_string((*p)->pkgpath()); this->write_c_string("\n"); + + this->packages_[*p] = package_index; + package_index++; } } @@ -983,6 +1105,19 @@ Export::write_unsigned(unsigned value) this->write_c_string(buf); } +// Return the index of a package. + +int +Export::package_index(const Package* pkg) const +{ + Unordered_map(const Package *, int)::const_iterator p = + this->packages_.find(pkg); + go_assert(p != this->packages_.end()); + int index = p->second; + go_assert(index != 0); + return index; +} + // Return the index of a type. int diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h index 69fbd6e..e3932d4 100644 --- a/gcc/go/gofrontend/export.h +++ b/gcc/go/gofrontend/export.h @@ -201,6 +201,10 @@ class Export : public String_dump void write_unsigned(unsigned); + // Return the index of a package. + int + package_index(const Package* p) const; + private: Export(const Export&); Export& operator=(const Export&); @@ -255,7 +259,7 @@ class Export : public String_dump // Index number of next type. int type_index_; // Packages we have written out. - Unordered_set(const Package*) packages_; + Unordered_map(const Package*, int) packages_; }; // An export streamer that puts the export stream in a named section. @@ -354,6 +358,11 @@ class Export_function_body : public String_dump decrement_indent() { --this->indent_; } + // Return the index of a package. + int + package_index(const Package* p) const + { return this->exp_->package_index(p); } + // Return a reference to the completed body. const std::string& body() const diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 9d8c085..6aca5f8 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -87,6 +87,27 @@ Expression::do_export(Export_function_body*) const go_unreachable(); } +// Write a name to the export data. + +void +Expression::export_name(Export_function_body* efb, const Named_object* no) +{ + if (no->package() != NULL) + { + char buf[50]; + snprintf(buf, sizeof buf, "<p%d>", efb->package_index(no->package())); + efb->write_c_string(buf); + } + + if (!Gogo::is_hidden_name(no->name())) + efb->write_string(no->name()); + else + { + efb->write_c_string("."); + efb->write_string(Gogo::unpack_hidden_name(no->name())); + } +} + // Give an error saying that the value of the expression is not used. void @@ -842,29 +863,16 @@ Var_expression::do_address_taken(bool escapes) } } -// The cost to inline a variable reference. We currently only support -// references to parameters and local variables. - -int -Var_expression::do_inlining_cost() const -{ - if (this->variable_->is_variable()) - { - if (!this->variable_->var_value()->is_global()) - return 1; - } - else if (this->variable_->is_result_variable()) - return 1; - - return 0x100000; -} - // Export a reference to a variable. void Var_expression::do_export(Export_function_body* efb) const { - efb->write_string(Gogo::unpack_hidden_name(this->variable_->name())); + Named_object* no = this->variable_; + if (no->is_result_variable() || !no->var_value()->is_global()) + efb->write_string(Gogo::unpack_hidden_name(no->name())); + else + Expression::export_name(efb, no); } // Get the backend representation for a reference to a variable. @@ -17535,26 +17543,55 @@ Expression::import_expression(Import_expression* imp, Location loc) } if (ifb->saw_error()) return Expression::make_error(loc); - std::string id = ifb->read_identifier(); - if (id.empty()) + return Expression::import_identifier(ifb, loc); +} + +// Import an identifier in an expression. This is a reference to a +// variable or function. + +Expression* +Expression::import_identifier(Import_function_body* ifb, Location loc) +{ + std::string id; + Package* pkg; + bool is_exported; + if (!Import::read_qualified_identifier(ifb, &id, &pkg, &is_exported)) { if (!ifb->saw_error()) - go_error_at(imp->location(), - "import error: expected identifier at %lu", + go_error_at(ifb->location(), + "import error for %qs: bad qualified identifier at %lu", + ifb->name().c_str(), static_cast<unsigned long>(ifb->off())); ifb->set_saw_error(); return Expression::make_error(loc); } - Named_object* var = ifb->block()->bindings()->lookup(id); - if (var == NULL) + + Named_object* no = NULL; + if (pkg == NULL && is_exported) + no = ifb->block()->bindings()->lookup(id); + if (no == NULL) + { + const Package* ipkg = pkg; + if (ipkg == NULL) + ipkg = ifb->function()->package(); + if (!is_exported) + id = '.' + ipkg->pkgpath() + '.' + id; + no = ipkg->bindings()->lookup(id); + } + if (no == NULL) + no = ifb->gogo()->lookup_global(id.c_str()); + + if (no == NULL) { if (!ifb->saw_error()) - go_error_at(imp->location(), "import error: lookup of %qs failed", - id.c_str()); + go_error_at(ifb->location(), + "import error for %qs: lookup of %qs failed", + ifb->name().c_str(), id.c_str()); ifb->set_saw_error(); return Expression::make_error(loc); } - return Expression::make_var_reference(var, loc); + + return Expression::make_var_reference(no, loc); } // Class Expression_list. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index ea98fac..e17e8dc 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1201,6 +1201,10 @@ class Expression void report_error(const char*); + // Write a name to export data. + static void + export_name(Export_function_body* efb, const Named_object*); + // Child class implements dumping to a dump context. virtual void do_dump_expression(Ast_dump_context*) const = 0; @@ -1246,6 +1250,9 @@ class Expression static Expression* convert_interface_to_type(Type*, Expression*, Location); + static Expression* + import_identifier(Import_function_body*, Location); + // The expression classification. Expression_classification classification_; // The location in the input file. @@ -1410,7 +1417,8 @@ class Var_expression : public Expression { return this; } int - do_inlining_cost() const; + do_inlining_cost() const + { return 1; } void do_export(Export_function_body*) const; diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index e94c567..b97367c 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -5182,7 +5182,7 @@ Function::Function(Function_type* type, Named_object* enclosing, Block* block, 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), - is_inline_only_(false) + is_inline_only_(false), is_referenced_by_inline_(false) { } @@ -5534,12 +5534,12 @@ Function::defer_stack(Location location) // Export the function. void -Function::export_func(Export* exp, const std::string& name) const +Function::export_func(Export* exp, const Named_object* no) const { Block* block = NULL; if (this->export_for_inlining()) block = this->block_; - Function::export_func_with_type(exp, name, this->type_, this->results_, + Function::export_func_with_type(exp, no, this->type_, this->results_, this->is_method() && this->nointerface(), block, this->location_); } @@ -5547,7 +5547,7 @@ Function::export_func(Export* exp, const std::string& name) const // Export a function with a type. void -Function::export_func_with_type(Export* exp, const std::string& name, +Function::export_func_with_type(Export* exp, const Named_object* no, const Function_type* fntype, Function::Results* result_vars, bool nointerface, Block* block, Location loc) @@ -5571,7 +5571,21 @@ Function::export_func_with_type(Export* exp, const std::string& name, exp->write_c_string(") "); } - exp->write_string(name); + if (no->package() != NULL && !fntype->is_method()) + { + char buf[50]; + snprintf(buf, sizeof buf, "<p%d>", exp->package_index(no->package())); + exp->write_c_string(buf); + } + + const std::string& name(no->name()); + if (!Gogo::is_hidden_name(name)) + exp->write_string(name); + else + { + exp->write_c_string("."); + exp->write_string(Gogo::unpack_hidden_name(name)); + } exp->write_c_string(" ("); const Typed_identifier_list* parameters = fntype->parameters(); @@ -5677,8 +5691,9 @@ Function::export_func_with_type(Export* exp, const std::string& name, // Import a function. -void +bool Function::import_func(Import* imp, std::string* pname, + Package** ppkg, bool* pis_exported, Typed_identifier** preceiver, Typed_identifier_list** pparameters, Typed_identifier_list** presults, @@ -5711,7 +5726,13 @@ Function::import_func(Import* imp, std::string* pname, imp->require_c_string(") "); } - *pname = imp->read_identifier(); + if (!Import::read_qualified_identifier(imp, pname, ppkg, pis_exported)) + { + go_error_at(imp->location(), + "import error at %d: bad function name in export data", + imp->pos()); + return false; + } Typed_identifier_list* parameters; *is_varargs = false; @@ -5812,11 +5833,13 @@ Function::import_func(Import* imp, std::string* pname, { go_error_at(imp->location(), "invalid inline function length %s", lenstr.c_str()); - return; + return false; } *body = imp->read(static_cast<size_t>(llen)); } + + return true; } // Get the backend representation. @@ -5829,7 +5852,10 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) unsigned int flags = 0; bool is_init_fn = false; if (no->package() != NULL) - ; + { + // Functions defined in other packages must be visible. + flags |= Backend::function_is_visible; + } else if (this->enclosing_ != NULL || Gogo::is_thunk(no)) ; else if (Gogo::unpack_hidden_name(no->name()) == "init" @@ -5877,6 +5903,11 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) else asm_name = gogo->function_asm_name(no->name(), no->package(), rtype); + // If an inline body refers to this function, then it + // needs to be visible in the symbol table. + if (this->is_referenced_by_inline_) + flags |= Backend::function_is_visible; + // 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 @@ -7015,7 +7046,8 @@ Variable::Variable(Type* type, Expression* init, bool is_global, type_from_init_tuple_(false), type_from_range_index_(false), type_from_range_value_(false), type_from_chan_element_(false), is_type_switch_var_(false), determined_type_(false), - in_unique_section_(false), toplevel_decl_(NULL) + in_unique_section_(false), is_referenced_by_inline_(false), + toplevel_decl_(NULL) { go_assert(type != NULL || init != NULL); go_assert(!is_parameter || init == NULL); @@ -7497,11 +7529,25 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, // Export the variable void -Variable::export_var(Export* exp, const std::string& name) const +Variable::export_var(Export* exp, const Named_object* no) const { go_assert(this->is_global_); exp->write_c_string("var "); - exp->write_string(name); + if (no->package() != NULL) + { + char buf[50]; + snprintf(buf, sizeof buf, "<p%d>", exp->package_index(no->package())); + exp->write_c_string(buf); + } + + if (!Gogo::is_hidden_name(no->name())) + exp->write_string(no->name()); + else + { + exp->write_c_string("."); + exp->write_string(Gogo::unpack_hidden_name(no->name())); + } + exp->write_c_string(" "); exp->write_type(this->type()); exp->write_c_string("\n"); @@ -7509,15 +7555,23 @@ Variable::export_var(Export* exp, const std::string& name) const // Import a variable. -void -Variable::import_var(Import* imp, std::string* pname, Type** ptype) +bool +Variable::import_var(Import* imp, std::string* pname, Package** ppkg, + bool* pis_exported, Type** ptype) { imp->require_c_string("var "); - *pname = imp->read_identifier(); + if (!Import::read_qualified_identifier(imp, pname, ppkg, pis_exported)) + { + go_error_at(imp->location(), + "import error at %d: bad variable name in export data", + imp->pos()); + return false; + } imp->require_c_string(" "); *ptype = imp->read_type(); imp->require_semicolon_if_old_version(); imp->require_c_string("\n"); + return true; } // Convert a variable to the backend representation. @@ -7568,6 +7622,18 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, && var_name == "runtime.writeBarrier") is_hidden = false; + // If an inline body refers to this variable, then it + // needs to be visible in the symbol table. + if (this->is_referenced_by_inline_) + is_hidden = false; + + // If this variable is in a different package, then it + // can't be treated as a hidden symbol. This case can + // arise when an inlined function refers to a + // package-scope unexported variable. + if (package != NULL) + is_hidden = false; + bvar = backend->global_variable(var_name, asm_name, btype, @@ -8145,11 +8211,11 @@ Named_object::export_named_object(Export* exp) const break; case NAMED_OBJECT_FUNC_DECLARATION: - this->func_declaration_value()->export_func(exp, this->name_); + this->func_declaration_value()->export_func(exp, this); break; case NAMED_OBJECT_VAR: - this->var_value()->export_var(exp, this->name_); + this->var_value()->export_var(exp, this); break; case NAMED_OBJECT_RESULT_VAR: @@ -8157,7 +8223,7 @@ Named_object::export_named_object(Export* exp) const go_unreachable(); case NAMED_OBJECT_FUNC: - this->func_value()->export_func(exp, this->name_); + this->func_value()->export_func(exp, this); break; } } diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index fd28ed1..5b77d6d 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -1486,6 +1486,11 @@ class Function set_is_inline_only() { this->is_inline_only_ = true; } + // Mark the function as referenced by an inline body. + void + set_is_referenced_by_inline() + { this->is_referenced_by_inline_ = true; } + // Swap with another function. Used only for the thunk which calls // recover. void @@ -1538,17 +1543,18 @@ class Function // Export the function. void - export_func(Export*, const std::string& name) const; + export_func(Export*, const Named_object*) const; // Export a function with a type. static void - export_func_with_type(Export*, const std::string& name, + export_func_with_type(Export*, const Named_object*, const Function_type*, Results*, bool nointerface, Block* block, Location); - // Import a function. - static void - import_func(Import*, std::string* pname, Typed_identifier** receiver, + // Import a function. Reports whether the import succeeded. + static bool + import_func(Import*, std::string* pname, Package** pkg, + bool* is_exported, Typed_identifier** receiver, Typed_identifier_list** pparameters, Typed_identifier_list** presults, bool* is_varargs, bool* nointerface, std::string* body); @@ -1628,6 +1634,9 @@ class Function // True if this function is inline only: if it should not be emitted // if it is not inlined. bool is_inline_only_ : 1; + // True if this function is referenced from an inlined body that + // will be put into the export data. + bool is_referenced_by_inline_ : 1; }; // A snapshot of the current binding state. @@ -1768,9 +1777,9 @@ class Function_declaration // Export a function declaration. void - export_func(Export* exp, const std::string& name) const + export_func(Export* exp, const Named_object* no) const { - Function::export_func_with_type(exp, name, this->fntype_, NULL, + Function::export_func_with_type(exp, no, this->fntype_, NULL, this->is_method() && this->nointerface(), NULL, this->location_); } @@ -2022,6 +2031,14 @@ class Variable this->in_unique_section_ = true; } + // Mark the variable as referenced by an inline body. + void + set_is_referenced_by_inline() + { + go_assert(this->is_global_); + this->is_referenced_by_inline_ = true; + } + // Return the top-level declaration for this variable. Statement* toplevel_decl() @@ -2062,11 +2079,12 @@ class Variable // Export the variable. void - export_var(Export*, const std::string& name) const; + export_var(Export*, const Named_object*) const; - // Import a variable. - static void - import_var(Import*, std::string* pname, Type** ptype); + // Import a variable. Reports whether the import succeeded. + static bool + import_var(Import*, std::string* pname, Package** pkg, bool* is_exported, + Type** ptype); private: // The type of a tuple. @@ -2133,6 +2151,9 @@ class Variable // True if this variable should be put in a unique section. This is // used for field tracking. bool in_unique_section_ : 1; + // True if this variable is referenced from an inlined body that + // will be put into the export data. + bool is_referenced_by_inline_ : 1; // The top-level declaration for this variable. Only used for local // variables. Must be a Temporary_statement if not NULL. Statement* toplevel_decl_; diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index c1982eb..ff92b82 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -288,8 +288,8 @@ Import::find_object_export_data(const std::string& filename, Import::Import(Stream* stream, Location location) : gogo_(NULL), stream_(stream), location_(location), package_(NULL), - add_to_globals_(false), type_data_(), type_pos_(0), type_offsets_(), - builtin_types_((- SMALLEST_BUILTIN_CODE) + 1), + add_to_globals_(false), packages_(), type_data_(), type_pos_(0), + type_offsets_(), builtin_types_((- SMALLEST_BUILTIN_CODE) + 1), types_(), version_(EXPORT_FORMAT_UNKNOWN) { } @@ -487,6 +487,8 @@ Import::read_one_import() Package* p = this->gogo_->register_package(pkgpath, "", Linemap::unknown_location()); p->set_package_name(package_name, this->location()); + + this->packages_.push_back(p); } // Read an indirectimport line. @@ -503,6 +505,8 @@ Import::read_one_indirect_import() Package* p = this->gogo_->register_package(pkgpath, "", Linemap::unknown_location()); p->set_package_name(package_name, this->location()); + + this->packages_.push_back(p); } // Read the list of import control functions and/or init graph. @@ -721,12 +725,19 @@ void Import::import_var() { std::string name; + Package* vpkg; + bool is_exported; Type* type; - Variable::import_var(this, &name, &type); + if (!Variable::import_var(this, &name, &vpkg, &is_exported, &type)) + return; + if (vpkg == NULL) + vpkg = this->package_; + if (!is_exported) + name = '.' + vpkg->pkgpath() + '.' + name; Variable* var = new Variable(type, NULL, true, false, false, this->location_); Named_object* no; - no = this->package_->add_variable(name, var); + no = vpkg->add_variable(name, var); if (this->add_to_globals_) this->gogo_->add_dot_import_object(no); } @@ -735,18 +746,26 @@ Import::import_var() // THIS->PACKAGE_, but it will be different for a method associated // with a type defined in a different package. -Named_object* +void Import::import_func(Package* package) { std::string name; + Package* fpkg; + bool is_exported; Typed_identifier* receiver; Typed_identifier_list* parameters; Typed_identifier_list* results; bool is_varargs; bool nointerface; std::string body; - Function::import_func(this, &name, &receiver, ¶meters, &results, - &is_varargs, &nointerface, &body); + if (!Function::import_func(this, &name, &fpkg, &is_exported, &receiver, + ¶meters, &results, &is_varargs, &nointerface, + &body)) + return; + if (fpkg == NULL) + fpkg = package; + if (!is_exported) + name = '.' + fpkg->pkgpath() + '.' + name; Function_type *fntype = Type::make_function_type(receiver, parameters, results, this->location_); if (is_varargs) @@ -768,13 +787,13 @@ Import::import_func(Package* package) rtype = rtype->points_to(); if (rtype->is_error_type()) - return NULL; + return; else if (rtype->named_type() != NULL) - no = rtype->named_type()->add_method_declaration(name, package, fntype, + no = rtype->named_type()->add_method_declaration(name, fpkg, fntype, loc); else if (rtype->forward_declaration_type() != NULL) no = rtype->forward_declaration_type()->add_method_declaration(name, - package, + fpkg, fntype, loc); else @@ -782,7 +801,7 @@ Import::import_func(Package* package) } else { - no = package->add_function_declaration(name, fntype, loc); + no = fpkg->add_function_declaration(name, fntype, loc); if (this->add_to_globals_) this->gogo_->add_dot_import_object(no); } @@ -791,8 +810,6 @@ Import::import_func(Package* package) no->func_declaration_value()->set_nointerface(); if (!body.empty() && !no->func_declaration_value()->has_imported_body()) no->func_declaration_value()->set_imported_body(this, body); - - return no; } // Read a type definition and initialize the entry in this->types_. @@ -1233,6 +1250,60 @@ Import::read_identifier() return ret; } +// Read a possibly qualified identifier from IMP. The qualification +// is <pID>, where ID is a package number. If the name has a leading +// '.', it is not exported; otherwise, it is. Set *NAME, *PKG and +// *IS_EXPORTED. Reports whether the read succeeded. + +bool +Import::read_qualified_identifier(Import_expression* imp, std::string* name, + Package** pkg, bool* is_exported) +{ + *pkg = NULL; + if (imp->match_c_string("<p")) + { + imp->advance(2); + char buf[50]; + char *pbuf = &buf[0]; + while (true) + { + int next = imp->peek_char(); + if (next == -1 || static_cast<size_t>(pbuf - buf) >= sizeof buf - 1) + return false; + if (next == '>') + { + imp->advance(1); + break; + } + *pbuf = static_cast<char>(next); + ++pbuf; + imp->advance(1); + } + + *pbuf = '\0'; + char *end; + long index = strtol(buf, &end, 10); + if (*end != '\0' + || index <= 0 + || static_cast<size_t>(index) > imp->max_package_index()) + return false; + + *pkg = imp->package_at_index(index); + go_assert(*pkg != NULL); + } + + *is_exported = true; + if (imp->match_c_string(".")) + { + imp->advance(1); + *is_exported = false; + } + + *name = imp->read_identifier(); + + return !name->empty(); +} + // Read a name from the stream. std::string diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h index c46a37e..ab30aed 100644 --- a/gcc/go/gofrontend/import.h +++ b/gcc/go/gofrontend/import.h @@ -72,6 +72,14 @@ class Import_expression virtual Type* read_type() = 0; + // Return the maximum valid package index. + virtual size_t + max_package_index() const = 0; + + // Return the package for a package index. + virtual Package* + package_at_index(int index) = 0; + // Return the version number of the export data we're reading. virtual Export_data_version version() const = 0; @@ -257,6 +265,11 @@ class Import : public Import_expression advance(size_t skip) { this->stream_->advance(skip); } + // Stream position, for error reporting. + int + pos() + { return this->stream_->pos(); } + // Return the version number of the export data we're reading. Export_data_version version() const { return this->version_; } @@ -279,6 +292,18 @@ class Import : public Import_expression std::string read_name(); + // Return the maximum valid package index. This is the size of + // packages_ because we will subtract 1 in package_at_index. + size_t + max_package_index() const + { return this->packages_.size(); } + + // Return the package at an index. (We subtract 1 because package + // index 0 is not used.) + Package* + package_at_index(int index) + { return this->packages_.at(index - 1); } + // Read a type. Type* read_type(); @@ -304,6 +329,12 @@ class Import : public Import_expression ifb() { return NULL; } + // Read a qualified identifier from an Import_expression. Sets + // *NAME, *PKG, and *IS_EXPORTED, and reports whether it succeeded. + static bool + read_qualified_identifier(Import_expression*, std::string* name, + Package** pkg, bool* is_exported); + private: static Stream* try_package_in_directory(const std::string&, Location); @@ -360,7 +391,7 @@ class Import : public Import_expression import_var(); // Import a function. - Named_object* + void import_func(Package*); // Parse a type definition. @@ -401,6 +432,8 @@ class Import : public Import_expression // Whether to add new objects to the global scope, rather than to a // package scope. bool add_to_globals_; + // Mapping from package index to package. + std::vector<Package*> packages_; // All type data. std::string type_data_; // Position of type data in the stream. @@ -567,6 +600,11 @@ class Import_function_body : public Import_expression location() const { return this->imp_->location(); } + // The function we are importing. + Named_object* + function() const + { return this->named_object_; } + // A reference to the body we are reading. const std::string& body() const @@ -662,6 +700,16 @@ class Import_function_body : public Import_expression ifb() { return this; } + // Return the maximum valid package index. + size_t + max_package_index() const + { return this->imp_->max_package_index(); } + + // Return the package at an index. + Package* + package_at_index(int index) + { return this->imp_->package_at_index(index); } + // Return whether we have seen an error. bool saw_error() const |