-95784e8eec75cfeb2363fb22b51085380e564af9
+37a47e4691b4602dd167f82c64a6569019584a80
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
#include "gogo.h"
#include "types.h"
+#include "expressions.h"
#include "statements.h"
#include "export.h"
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.
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();
// 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
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())
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();
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.
this->write_c_string(" ");
this->write_string((*p)->pkgpath());
this->write_c_string("\n");
+
+ this->packages_[*p] = package_index;
+ package_index++;
}
}
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
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&);
// 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.
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
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
}
}
-// 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.
}
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.
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;
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.
{ return this; }
int
- do_inlining_cost() const;
+ do_inlining_cost() const
+ { return 1; }
void
do_export(Export_function_body*) const;
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)
{
}
// 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_);
}
// 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)
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();
// 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,
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;
{
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.
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"
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
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);
// 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");
// 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.
&& 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,
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:
go_unreachable();
case NAMED_OBJECT_FUNC:
- this->func_value()->export_func(exp, this->name_);
+ this->func_value()->export_func(exp, this);
break;
}
}
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
// 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);
// 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.
// 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_);
}
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()
// 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.
// 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_;
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)
{
}
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.
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.
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);
}
// 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)
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
}
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);
}
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_.
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
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;
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_; }
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();
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);
import_var();
// Import a function.
- Named_object*
+ void
import_func(Package*);
// Parse a type definition.
// 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.
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
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