From patchwork Wed Nov 28 00:08:23 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 202326 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id EECC22C0086 for ; Wed, 28 Nov 2012 11:08:41 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1354666122; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:From:To:Subject:Date:Message-ID:User-Agent:MIME-Version: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=dH84pFY ADyVtnJ7v4Dn9Zt8XAhg=; b=vT62DdL5JMuVdbWdBgSEVQ6aDcDgLC9mvC4gVSL GTUGQgm9aqkGNLJOxqWvR8vIYmzazZggOR9WjGQoR26aBVF3BCOfbue2O3KdRG9k RdOCXskEvSJ0YHMBuMO50jx7IxSU5znyyba5FztuV/iKwd3ulLJJIPv+5Gfqnr4r SUSo= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:X-Google-DKIM-Signature:Received:Received:From:To:Subject:Date:Message-ID:User-Agent:MIME-Version:Content-Type:X-Gm-Message-State:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=C9ISr+3RTTNog2CZlqvTecXEL28qh5DMJkPbA5PRdfqc5hhEokv0BrbQnXlxol RfqCJq6PYEPThCdQP8rhhgM0kgwjjPqZ37n8jwv+gligrTqKdDNE/sEXAO6vlUUl JoCzEkf4o620XFtdp82yML0R33ioPSdGzRGUGzNGKTijo=; Received: (qmail 14715 invoked by alias); 28 Nov 2012 00:08:35 -0000 Received: (qmail 14705 invoked by uid 22791); 28 Nov 2012 00:08:32 -0000 X-SWARE-Spam-Status: No, hits=-4.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FILL_THIS_FORM, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE, RP_MATCHES_RCVD, TW_FN, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from mail-pa0-f47.google.com (HELO mail-pa0-f47.google.com) (209.85.220.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 28 Nov 2012 00:08:26 +0000 Received: by mail-pa0-f47.google.com with SMTP id fa10so3837587pad.20 for ; Tue, 27 Nov 2012 16:08:26 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:subject:date:message-id:user-agent:mime-version :content-type:x-gm-message-state; bh=Vbv46QaAgXpSmJHR7IxYMeAzM7cFZKHqi7mNeMsDBVQ=; b=kzun6CBaveKiY2j9TBdzgXjhQoOb5barc6f4mhAg6jvsczOUJxh7ViF+dM3t3Uvfho mDQyeiuc4Y3EBlfxCX5QKocRUNT/kkwhnmIWpwvnCsoXwKZPD03cnfFawewQeqMONekH 1fWOXVir/TD9aivQg2Vob9/VAHjhOhgsuZ9zS3whhws/B1DSAUdW88sIWXvHzQkN7hPd PsnT5jh3SbXaX3cGPxHTXfNA6XDLW9Oh2+JB5j6y4ZfAPtz9+jpGLJSW8G7fkO8unnqh m4gc3clAnPEqbgIshxWIom0Id1y/+S+mRlra4/DP9Ly+sfQ5UhwLtSqQNjPsOcklyKRs oFyQ== Received: by 10.68.223.131 with SMTP id qu3mr52317919pbc.89.1354061306080; Tue, 27 Nov 2012 16:08:26 -0800 (PST) Received: from coign.google.com ([2620:0:1000:1804:224:d7ff:fe8f:f634]) by mx.google.com with ESMTPS id vk5sm11389157pbc.34.2012.11.27.16.08.23 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 27 Nov 2012 16:08:24 -0800 (PST) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: Go patch committed: Implement //go:nointerface Date: Tue, 27 Nov 2012 16:08:23 -0800 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-Gm-Message-State: ALoCoQlXY0FaqPSelu5l4Fok16hDaAZs16mYl49OFS3ct9DneCOIgSS5luf0rQEIq2y/5hMAlGcC+XrtFeoG6zeORUfXV+nvngd5K00qdUSgsBa0FQEQJXvOezTBT/p6dXM5zBEitWIJ/cU6EEm5DSNEUg7UUp8Jt4E59q6udHBQzRuzEDHOEgeG8Sc/emX++CI4ix1q8OM3 X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org As part of a code analysis experiment, the gc compiler implements a feature based on comments: if a //go:nointerface comment appears before a method for a type, that method is not included in any interfaces. This works in conjunction with a field tracking feature, not yet implemented in gccgo, that lets a program determine which struct fields are actually referenced. This patch implements //go:nointerface for gccgo. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline. Ian diff -r 2fe578353c73 go/gogo.cc --- a/go/gogo.cc Sat Nov 24 16:51:19 2012 -0800 +++ b/go/gogo.cc Tue Nov 27 16:05:11 2012 -0800 @@ -3074,8 +3074,8 @@ : 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 -r 2fe578353c73 go/gogo.h --- a/go/gogo.h Sat Nov 24 16:51:19 2012 -0800 +++ b/go/gogo.h Tue Nov 27 16:05:11 2012 -0800 @@ -911,6 +911,24 @@ 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 @@ 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 -r 2fe578353c73 go/lex.cc --- a/go/lex.cc Sat Nov 24 16:51:19 2012 -0800 +++ b/go/lex.cc Tue Nov 27 16:05:11 2012 -0800 @@ -442,7 +442,8 @@ 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 @@ 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 -r 2fe578353c73 go/lex.h --- a/go/lex.h Sat Nov 24 16:51:19 2012 -0800 +++ b/go/lex.h Tue Nov 27 16:05:11 2012 -0800 @@ -349,6 +349,16 @@ 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 @@ 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 -r 2fe578353c73 go/parse.cc --- a/go/parse.cc Sat Nov 24 16:51:19 2012 -0800 +++ b/go/parse.cc Tue Nov 27 16:05:11 2012 -0800 @@ -1280,6 +1280,12 @@ 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 @@ 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 @@ // 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 @@ 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 @@ } } } + + if (saw_nointerface) + warning_at(location, 0, + ("ignoring magic //go:nointerface comment " + "before declaration")); } else { @@ -2268,9 +2288,13 @@ 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 -r 2fe578353c73 go/parse.h --- a/go/parse.h Sat Nov 24 16:51:19 2012 -0800 +++ b/go/parse.h Tue Nov 27 16:05:11 2012 -0800 @@ -214,7 +214,7 @@ 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 -r 2fe578353c73 go/types.cc --- a/go/types.cc Sat Nov 24 16:51:19 2012 -0800 +++ b/go/types.cc Tue Nov 27 16:05:11 2012 -0800 @@ -2068,6 +2068,13 @@ 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 @@ } 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 @@ 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_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 -r 2fe578353c73 go/types.h --- a/go/types.h Sat Nov 24 16:51:19 2012 -0800 +++ b/go/types.h Tue Nov 27 16:05:11 2012 -0800 @@ -179,6 +179,12 @@ 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 @@ 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 @@ 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 @@ 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_;