Commit f6338016 by Ian Lance Taylor

compiler: Implement //go:nointerface comments.

From-SVN: r193874
parent cfbeaedf
......@@ -3074,8 +3074,8 @@ Function::Function(Function_type* type, Function* enclosing, Block* block,
: type_(type), enclosing_(enclosing), results_(NULL),
closure_var_(NULL), block_(block), location_(location), labels_(),
local_type_count_(0), fndecl_(NULL), defer_stack_(NULL),
results_are_named_(false), calls_recover_(false), is_recover_thunk_(false),
has_recover_thunk_(false)
results_are_named_(false), nointerface_(false), calls_recover_(false),
is_recover_thunk_(false), has_recover_thunk_(false)
{
}
......
......@@ -911,6 +911,24 @@ class Function
results_are_named() const
{ return this->results_are_named_; }
// Whether this method should not be included in the type
// descriptor.
bool
nointerface() const
{
go_assert(this->is_method());
return this->nointerface_;
}
// Record that this method should not be included in the type
// descriptor.
void
set_nointerface()
{
go_assert(this->is_method());
this->nointerface_ = true;
}
// Add a new field to the closure variable.
void
add_closure_field(Named_object* var, Location loc)
......@@ -1113,6 +1131,8 @@ class Function
Temporary_statement* defer_stack_;
// True if the result variables are named.
bool results_are_named_;
// True if this method should not be included in the type descriptor.
bool nointerface_;
// True if this function calls the predeclared recover function.
bool calls_recover_;
// True if this a thunk built for a function which calls recover.
......
......@@ -442,7 +442,8 @@ Token::print(FILE* file) const
Lex::Lex(const char* input_file_name, FILE* input_file, Linemap* linemap)
: 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), extern_()
lineoff_(0), lineno_(0), add_semi_at_eol_(false), saw_nointerface_(false),
extern_()
{
this->linebuf_ = new char[this->linebufsize_];
this->linemap_->start_file(input_file_name, 0);
......@@ -1704,6 +1705,12 @@ Lex::skip_cpp_comment()
this->extern_ = std::string(p, plend - p);
}
// For field tracking analysis: a //go:nointerface comment means
// that the next interface method should not be stored in the type
// descriptor. This permits it to be discarded if it is not needed.
if (this->lineoff_ == 2 && memcmp(p, "go:nointerface", 14) == 0)
this->saw_nointerface_ = true;
while (p < pend)
{
this->lineoff_ = p - this->linebuf_;
......
......@@ -349,6 +349,16 @@ class Lex
extern_name() const
{ return this->extern_; }
// Return whether we have seen a //go:nointerface comment, clearing
// the flag.
bool
get_and_clear_nointerface()
{
bool ret = this->saw_nointerface_;
this->saw_nointerface_ = false;
return ret;
}
// Return whether the identifier NAME should be exported. NAME is a
// mangled name which includes only ASCII characters.
static bool
......@@ -483,6 +493,8 @@ class Lex
size_t lineno_;
// Whether to add a semicolon if we see a newline now.
bool add_semi_at_eol_;
// Whether we just saw a magic go:nointerface comment.
bool saw_nointerface_;
// The external name to use for a function declaration, from a magic
// //extern comment.
std::string extern_;
......
......@@ -1280,6 +1280,12 @@ void
Parse::declaration()
{
const Token* token = this->peek_token();
bool saw_nointerface = this->lex_->get_and_clear_nointerface();
if (saw_nointerface && !token->is_keyword(KEYWORD_FUNC))
warning_at(token->location(), 0,
"ignoring magic //go:nointerface comment before non-method");
if (token->is_keyword(KEYWORD_CONST))
this->const_decl();
else if (token->is_keyword(KEYWORD_TYPE))
......@@ -1287,7 +1293,7 @@ Parse::declaration()
else if (token->is_keyword(KEYWORD_VAR))
this->var_decl();
else if (token->is_keyword(KEYWORD_FUNC))
this->function_decl();
this->function_decl(saw_nointerface);
else
{
error_at(this->location(), "expected declaration");
......@@ -2166,8 +2172,11 @@ Parse::simple_var_decl_or_assignment(const std::string& name,
// inside the asm. This extension will be removed at some future
// date. It has been replaced with //extern comments.
// SAW_NOINTERFACE is true if we saw a magic //go:nointerface comment,
// which means that we omit the method from the type descriptor.
void
Parse::function_decl()
Parse::function_decl(bool saw_nointerface)
{
go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
Location location = this->location();
......@@ -2180,6 +2189,12 @@ Parse::function_decl()
rec = this->receiver();
token = this->peek_token();
}
else if (saw_nointerface)
{
warning_at(location, 0,
"ignoring magic //go:nointerface comment before non-method");
saw_nointerface = false;
}
if (!token->is_identifier())
{
......@@ -2256,6 +2271,11 @@ Parse::function_decl()
}
}
}
if (saw_nointerface)
warning_at(location, 0,
("ignoring magic //go:nointerface comment "
"before declaration"));
}
else
{
......@@ -2268,9 +2288,13 @@ Parse::function_decl()
this->gogo_->add_erroneous_name(name);
name = this->gogo_->pack_hidden_name("_", false);
}
this->gogo_->start_function(name, fntype, true, location);
named_object = this->gogo_->start_function(name, fntype, true, location);
Location end_loc = this->block();
this->gogo_->finish_function(end_loc);
if (saw_nointerface
&& !this->is_erroneous_function_
&& named_object->is_function())
named_object->func_value()->set_nointerface();
this->is_erroneous_function_ = hold_is_erroneous_function;
}
}
......
......@@ -214,7 +214,7 @@ class Parse
void simple_var_decl_or_assignment(const std::string&, Location,
bool may_be_composite_lit,
Range_clause*, Type_switch*);
void function_decl();
void function_decl(bool saw_nointerface);
Typed_identifier* receiver();
Expression* operand(bool may_be_sink);
Expression* enclosing_var_reference(Named_object*, Named_object*,
......
......@@ -2068,6 +2068,13 @@ Type::methods_constructor(Gogo* gogo, Type* methods_type,
continue;
if (only_value_methods && !p->second->is_value_method())
continue;
// This is where we implement the magic //go:nointerface
// comment. If we saw that comment, we don't add this
// method to the type descriptor.
if (p->second->nointerface())
continue;
smethods.push_back(std::make_pair(p->first, p->second));
}
}
......@@ -6891,6 +6898,24 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const
}
return false;
}
// If the magic //go:nointerface comment was used, the method
// may not be used to implement interfaces.
if (m->nointerface())
{
if (reason != NULL)
{
std::string n = Gogo::message_name(p->name());
size_t len = 100 + n.length();
char* buf = new char[len];
snprintf(buf, len,
_("method %s%s%s is marked go:nointerface"),
open_quote, n.c_str(), close_quote);
reason->assign(buf);
delete[] buf;
}
return false;
}
}
return true;
......@@ -7530,6 +7555,15 @@ Named_method::do_bind_method(Expression* expr, Location location) const
return bme;
}
// Return whether this method should not participate in interfaces.
bool
Named_method::do_nointerface() const
{
Named_object* no = this->named_object_;
return no->is_function() && no->func_value()->nointerface();
}
// Class Interface_method.
// Bind a method to an object.
......@@ -8834,6 +8868,9 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods,
Type::build_one_stub_method(gogo, m, buf, stub_params,
fntype->is_varargs(), location);
gogo->finish_function(fntype->location());
if (m->nointerface() && stub->is_function())
stub->func_value()->set_nointerface();
}
m->set_stub_object(stub);
......
......@@ -179,6 +179,12 @@ class Method
this->stub_ = no;
}
// Return true if this method should not participate in any
// interfaces.
bool
nointerface() const
{ return this->do_nointerface(); }
protected:
// These objects are only built by the child classes.
Method(const Field_indexes* field_indexes, unsigned int depth,
......@@ -204,6 +210,10 @@ class Method
virtual Expression*
do_bind_method(Expression* expr, Location location) const = 0;
// Return whether this method should not participate in interfaces.
virtual bool
do_nointerface() const = 0;
private:
// The sequence of field indexes used for this method. If this is
// NULL, then the method is defined for the current type.
......@@ -254,6 +264,10 @@ class Named_method : public Method
Expression*
do_bind_method(Expression* expr, Location location) const;
// Return whether this method should not participate in interfaces.
bool
do_nointerface() const;
private:
// The method itself. For a method which needs a stub, this starts
// out as the underlying method, and is later replaced with the stub
......@@ -295,6 +309,11 @@ class Interface_method : public Method
Expression*
do_bind_method(Expression* expr, Location location) const;
// Return whether this method should not participate in interfaces.
bool
do_nointerface() const
{ return false; }
private:
// The name of the interface method to call.
std::string name_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment