aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2012-11-28 00:08:16 +0000
committerIan Lance Taylor <iant@google.com>2012-11-28 00:08:16 +0000
commit2a2a9b991cd4b709e2f8198ff59d7e649b694f27 (patch)
tree35fac20e209e18c93ef872452387ae58623599d0 /gcc/go
parent4460b49831aa8dcdb93753aae83b50207988edd4 (diff)
compiler: Implement //go:nointerface comments.
git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@193874 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/gogo.cc4
-rw-r--r--gcc/go/gofrontend/gogo.h20
-rw-r--r--gcc/go/gofrontend/lex.cc9
-rw-r--r--gcc/go/gofrontend/lex.h12
-rw-r--r--gcc/go/gofrontend/parse.cc30
-rw-r--r--gcc/go/gofrontend/parse.h2
-rw-r--r--gcc/go/gofrontend/types.cc37
-rw-r--r--gcc/go/gofrontend/types.h19
8 files changed, 126 insertions, 7 deletions
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 5b566103ec8..766fe908095 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -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)
{
}
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 8759d32b6c9..e23b3c65072 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -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.
diff --git a/gcc/go/gofrontend/lex.cc b/gcc/go/gofrontend/lex.cc
index 6add84ed1f7..804146d0e9f 100644
--- a/gcc/go/gofrontend/lex.cc
+++ b/gcc/go/gofrontend/lex.cc
@@ -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_;
diff --git a/gcc/go/gofrontend/lex.h b/gcc/go/gofrontend/lex.h
index 074bbaea4ed..fc9258b880a 100644
--- a/gcc/go/gofrontend/lex.h
+++ b/gcc/go/gofrontend/lex.h
@@ -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_;
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index 72059b88a55..fe463c7d66f 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -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;
}
}
diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h
index a355b7d2b3b..9743bb52ebf 100644
--- a/gcc/go/gofrontend/parse.h
+++ b/gcc/go/gofrontend/parse.h
@@ -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*,
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 1990b03c3f8..7a4345dfa2c 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -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);
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index a62a6cfbf97..2ab21f65355 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -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_;