compiler: track //go:nointerface in export data

The magic //go:nointerface comment, used for field tracking, was only
    implemented for conversions to interface types in the same package.
    Record it in the export data, so that it works as expected for types
    imported from a different package.
    
    Reviewed-on: https://go-review.googlesource.com/93075

From-SVN: r257540
This commit is contained in:
Ian Lance Taylor 2018-02-09 19:39:14 +00:00
parent 0444aa9c0a
commit 8221fb01d6
5 changed files with 81 additions and 9 deletions

View File

@ -1,4 +1,4 @@
7e94bac5676afc8188677c98ecb263c78c1a7f8d
89105404f94005ffa8e2b08df78015dc9ac91362
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -5189,17 +5189,24 @@ Function::defer_stack(Location location)
void
Function::export_func(Export* exp, const std::string& name) const
{
Function::export_func_with_type(exp, name, this->type_);
Function::export_func_with_type(exp, name, this->type_,
this->is_method() && this->nointerface());
}
// Export a function with a type.
void
Function::export_func_with_type(Export* exp, const std::string& name,
const Function_type* fntype)
const Function_type* fntype, bool nointerface)
{
exp->write_c_string("func ");
if (nointerface)
{
go_assert(fntype->is_method());
exp->write_c_string("/*nointerface*/ ");
}
if (fntype->is_method())
{
exp->write_c_string("(");
@ -5280,10 +5287,21 @@ Function::import_func(Import* imp, std::string* pname,
Typed_identifier** preceiver,
Typed_identifier_list** pparameters,
Typed_identifier_list** presults,
bool* is_varargs)
bool* is_varargs,
bool* nointerface)
{
imp->require_c_string("func ");
*nointerface = false;
if (imp->match_c_string("/*"))
{
imp->require_c_string("/*nointerface*/ ");
*nointerface = true;
// Only a method can be nointerface.
go_assert(imp->peek_char() == '(');
}
*preceiver = NULL;
if (imp->peek_char() == '(')
{
@ -6213,6 +6231,32 @@ Bindings_snapshot::check_goto_defs(Location loc, const Block* block,
// Class Function_declaration.
// Whether this declares a method.
bool
Function_declaration::is_method() const
{
return this->fntype_->is_method();
}
// Whether this method should not be included in the type descriptor.
bool
Function_declaration::nointerface() const
{
go_assert(this->is_method());
return (this->pragmas_ & GOPRAGMA_NOINTERFACE) != 0;
}
// Record that this method should not be included in the type
// descriptor.
void
Function_declaration::set_nointerface()
{
this->pragmas_ |= GOPRAGMA_NOINTERFACE;
}
// Return the function descriptor.
Expression*

View File

@ -1476,13 +1476,14 @@ class Function
// Export a function with a type.
static void
export_func_with_type(Export*, const std::string& name,
const Function_type*);
const Function_type*, bool nointerface);
// Import a function.
static void
import_func(Import*, std::string* pname, Typed_identifier** receiver,
Typed_identifier_list** pparameters,
Typed_identifier_list** presults, bool* is_varargs);
Typed_identifier_list** presults, bool* is_varargs,
bool* nointerface);
private:
// Type for mapping from label names to Label objects.
@ -1607,6 +1608,10 @@ class Function_declaration
location() const
{ return this->location_; }
// Return whether this function declaration is a method.
bool
is_method() const;
const std::string&
asm_name() const
{ return this->asm_name_; }
@ -1628,6 +1633,16 @@ class Function_declaration
this->pragmas_ = pragmas;
}
// Whether this method should not be included in the type
// descriptor.
bool
nointerface() const;
// Record that this method should not be included in the type
// descriptor.
void
set_nointerface();
// Return an expression for the function descriptor, given the named
// object for this function. This may only be called for functions
// without a closure. This will be an immutable struct with one
@ -1652,7 +1667,10 @@ class Function_declaration
// Export a function declaration.
void
export_func(Export* exp, const std::string& name) const
{ Function::export_func_with_type(exp, name, this->fntype_); }
{
Function::export_func_with_type(exp, name, this->fntype_,
this->is_method() && this->nointerface());
}
// Check that the types used in this declaration's signature are defined.
void

View File

@ -607,8 +607,9 @@ Import::import_func(Package* package)
Typed_identifier_list* parameters;
Typed_identifier_list* results;
bool is_varargs;
bool nointerface;
Function::import_func(this, &name, &receiver,
&parameters, &results, &is_varargs);
&parameters, &results, &is_varargs, &nointerface);
Function_type *fntype = Type::make_function_type(receiver, parameters,
results, this->location_);
if (is_varargs)
@ -648,6 +649,10 @@ Import::import_func(Package* package)
if (this->add_to_globals_)
this->gogo_->add_dot_import_object(no);
}
if (nointerface)
no->func_declaration_value()->set_nointerface();
return no;
}

View File

@ -9742,7 +9742,12 @@ bool
Named_method::do_nointerface() const
{
Named_object* no = this->named_object_;
return no->is_function() && no->func_value()->nointerface();
if (no->is_function())
return no->func_value()->nointerface();
else if (no->is_function_declaration())
return no->func_declaration_value()->nointerface();
else
go_unreachable();
}
// Class Interface_method.