-d3636ca659ed7eed6d2e1cedfa0adccc6d81c07d
+85a9c6992d9660e36972c279a5252fd9591bb765
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
{
go_assert(filename_count > 0);
+ Lex::Linknames all_linknames;
for (unsigned int i = 0; i < filename_count; ++i)
{
if (i > 0)
if (strcmp(filename, "-") != 0)
fclose(file);
+
+ Lex::Linknames* linknames = lexer.get_and_clear_linknames();
+ if (linknames != NULL)
+ {
+ if (!::gogo->current_file_imported_unsafe())
+ {
+ for (Lex::Linknames::const_iterator p = linknames->begin();
+ p != linknames->end();
+ ++p)
+ error_at(p->second.loc,
+ ("//go:linkname only allowed in Go files that "
+ "import \"unsafe\""));
+ }
+ all_linknames.insert(linknames->begin(), linknames->end());
+ }
}
::gogo->linemap()->stop();
// define them now.
::gogo->define_global_names();
+ // Apply any go:linkname directives.
+ for (Lex::Linknames::const_iterator p = all_linknames.begin();
+ p != all_linknames.end();
+ ++p)
+ ::gogo->add_linkname(p->first, p->second.is_exported, p->second.ext_name,
+ p->second.loc);
+
// Finalize method lists and build stub methods for named types.
::gogo->finalize_methods();
file_block_names_(),
imports_(),
imported_unsafe_(false),
+ current_file_imported_unsafe_(false),
packages_(),
init_functions_(),
var_deps_(),
if (filename == "unsafe")
{
this->import_unsafe(local_name, is_local_name_exported, location);
+ this->current_file_imported_unsafe_ = true;
return;
}
this->current_bindings()->add_named_object(no);
}
+// Add a linkname. This implements the go:linkname compiler directive.
+// We only support this for functions and function declarations.
+
+void
+Gogo::add_linkname(const std::string& go_name, bool is_exported,
+ const std::string& ext_name, Location loc)
+{
+ Named_object* no =
+ this->package_->bindings()->lookup(this->pack_hidden_name(go_name,
+ is_exported));
+ if (no == NULL)
+ error_at(loc, "%s is not defined", go_name.c_str());
+ else if (no->is_function())
+ no->func_value()->set_asm_name(ext_name);
+ else if (no->is_function_declaration())
+ no->func_declaration_value()->set_asm_name(ext_name);
+ else
+ error_at(loc,
+ ("%s is not a function; "
+ "//go:linkname is only supported for functions"),
+ go_name.c_str());
+}
+
// Mark all local variables used. This is used when some types of
// parse error occur.
}
package->clear_used();
}
+
+ this->current_file_imported_unsafe_ = false;
}
// Queue up a type specific function for later writing. These are
}
}
+ if (!this->asm_name_.empty())
+ {
+ asm_name = this->asm_name_;
+ is_visible = true;
+ }
+
// 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
add_file_block_name(const std::string& name, Location location)
{ this->file_block_names_[name] = location; }
+ // Add a linkname, from the go:linkname compiler directive. This
+ // changes the externally visible name of go_name to be ext_name.
+ void
+ add_linkname(const std::string& go_name, bool is_exported,
+ const std::string& ext_name, Location location);
+
// Mark all local variables in current bindings as used. This is
// used when there is a parse error to avoid useless errors.
void
set_need_init_fn()
{ this->need_init_fn_ = true; }
+ // Return whether the current file imported the unsafe package.
+ bool
+ current_file_imported_unsafe() const
+ { return this->current_file_imported_unsafe_; }
+
// Clear out all names in file scope. This is called when we start
// parsing a new file.
void
Imports imports_;
// Whether the magic unsafe package was imported.
bool imported_unsafe_;
+ // Whether the magic unsafe package was imported by the current file.
+ bool current_file_imported_unsafe_;
// Mapping from package names we have seen to packages. This does
// not include the package we are compiling.
Packages packages_;
results_are_named() const
{ return this->results_are_named_; }
+ // Set the assembler name.
+ void
+ set_asm_name(const std::string& asm_name)
+ { this->asm_name_ = asm_name; }
+
// Set the pragmas for this function.
void
set_pragmas(unsigned int pragmas)
Labels labels_;
// The number of local types defined in this function.
unsigned int local_type_count_;
+ // The assembler name: this is the name that will be put in the object file.
+ // Set by the go:linkname compiler directive. This is normally empty.
+ std::string asm_name_;
// The function descriptor, if any.
Expression* descriptor_;
// The function decl.
: input_file_name_(input_file_name), input_file_(input_file),
linemap_(linemap), linebuf_(NULL), linebufsize_(120), linesize_(0),
lineoff_(0), lineno_(0), add_semi_at_eol_(false), pragmas_(0),
- extern_()
+ extern_(), linknames_(NULL)
{
this->linebuf_ = new char[this->linebufsize_];
this->linemap_->start_file(input_file_name, 0);
// //extern comment.
this->extern_.clear();
+ Location loc = this->location();
size_t lineoff = this->lineoff_;
const char* p = this->linebuf_ + lineoff;
{
// As in the gc compiler, set the external link name for a Go symbol.
std::string go_name;
- std::string c_name;
+ std::string ext_name;
+ bool is_exported = false;
if (ps < pend)
{
while (ps < pend && (*ps == ' ' || *ps == '\t'))
if (ps < pend)
{
const char* pg = ps;
+
+ unsigned int c;
+ bool issued_error;
+ ps = this->advance_one_utf8_char(ps, &c, &issued_error);
+ is_exported = Lex::is_unicode_uppercase(c);
+
while (ps < pend && *ps != ' ' && *ps != '\t')
++ps;
if (ps < pend)
while (ps < pend && *ps != ' ' && *ps != '\t')
++ps;
if (ps <= pend)
- c_name = std::string(pc, ps - pc);
+ ext_name = std::string(pc, ps - pc);
}
if (ps != pend)
{
go_name.clear();
- c_name.clear();
+ ext_name.clear();
}
}
- if (go_name.empty() || c_name.empty())
- error_at(this->location(), "usage: //go:linkname localname linkname");
+ if (go_name.empty() || ext_name.empty())
+ error_at(loc, "usage: //go:linkname localname linkname");
else
- this->linknames_[go_name] = c_name;
+ {
+ if (this->linknames_ == NULL)
+ this->linknames_ = new Linknames();
+ (*this->linknames_)[go_name] = Linkname(ext_name, is_exported, loc);
+ }
}
else if (verb == "go:nointerface")
{
return ret;
}
+ struct Linkname
+ {
+ std::string ext_name; // External name.
+ bool is_exported; // Whether the internal name is exported.
+ Location loc; // Location of go:linkname directive.
+
+ Linkname()
+ : ext_name(), is_exported(false), loc()
+ { }
+
+ Linkname(const std::string& ext_name_a, bool is_exported_a, Location loc_a)
+ : ext_name(ext_name_a), is_exported(is_exported_a), loc(loc_a)
+ { }
+ };
+
+ typedef std::map<std::string, Linkname> Linknames;
+
+ // Return the linknames seen so far, or NULL if none, and clear the
+ // set. These are from go:linkname compiler directives.
+ Linknames*
+ get_and_clear_linknames()
+ {
+ Linknames* ret = this->linknames_;
+ this->linknames_ = NULL;
+ return ret;
+ }
+
// Return whether the identifier NAME should be exported. NAME is a
// mangled name which includes only ASCII characters.
static bool
// The external name to use for a function declaration, from a magic
// //extern comment.
std::string extern_;
- // The list of //go:linkname comments.
- std::map<std::string, std::string> linknames_;
+ // The list of //go:linkname comments, if any.
+ Linknames* linknames_;
};
#endif // !defined(GO_LEX_H)