From patchwork Wed Jun 12 23:50:05 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 250931 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]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id A5E7B2C007B for ; Thu, 13 Jun 2013 09:50:23 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type; q=dns; s= default; b=qdzXH5jWuUA32AIbx6eKo36JapI0PjgN5cIlFsu0qGajYr09YsMtR CE/MsE+Xn2hNHDvNIGroQM8MGV8K+51bdYsFdAObnp9rfedvn9xdRxbmwAHaxf8d Gj4/VSb65pUg+736R1kBSW1sBWtWehUu8m3WcMxiB4PnJpfz2BgPNE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type; s= default; bh=DIAGn/LllbBCf8N/qqBO+HqQNOU=; b=qIxaj71sZa/28E1LeBrT 1pkM76ZfbWXKvmL5/BKSgzz4JMSeJpyFQoHvMBbj0mv3eQCS6vFvb5EcvDw8k34q GMSkfrzDu9Vb68dg4T3AQ8E70AQ5g5zn59xBWEzB2J8eb6H9VTtRV3Ns2/tnr/rZ ckvew3BPNxNPobtZ2TSkI7g= Received: (qmail 1654 invoked by alias); 12 Jun 2013 23:50:16 -0000 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 Received: (qmail 1637 invoked by uid 89); 12 Jun 2013 23:50:16 -0000 X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, RCVD_IN_HOSTKARMA_YE, RP_MATCHES_RCVD, SPF_PASS, TW_FN autolearn=ham version=3.3.1 Received: from mail-pd0-f180.google.com (HELO mail-pd0-f180.google.com) (209.85.192.180) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Wed, 12 Jun 2013 23:50:15 +0000 Received: by mail-pd0-f180.google.com with SMTP id 10so10647242pdi.11 for ; Wed, 12 Jun 2013 16:50:13 -0700 (PDT) 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=nUtKUK3GapaLGWHRcjpEnqGklnXS7BVtoD9wotvCIuw=; b=BOHD4p7c5cVZJFh97H3f9SN7Ir3a1vEQRHvPoZft24MDx9ZT9BnBo/jyFHRCN/+fFg z9nLh1+dutlY1b0hStvGjMxvdt4WpmD1Oh6laYG/aKEzrY+5egTYqbgydGAsnHhq7+Uz 9uI9OKI7QRvyxoriJQz15R0HhuuA4ljWk9VC9a+95hW5evteCfQ+RDDu2t9Sp8dtEzxq svKPbmnrkRb/thq6Kk5msv5BnWXG0JFMP2z9cX/r+dWwy45uVfxbhsURr9cS1CkvNH7B w/vW2l8WFcNZMDZNIAwRGGm7iAH2bgzKAWcI3Bja4Lq/RHE4NAU14Lj81gmBruWPfbbl 3Onw== X-Received: by 10.68.164.196 with SMTP id ys4mr22126361pbb.170.1371081013516; Wed, 12 Jun 2013 16:50:13 -0700 (PDT) Received: from iant-glaptop.roam.corp.google.com.google.com ([207.198.105.20]) by mx.google.com with ESMTPSA id so3sm23169378pac.14.2013.06.12.16.50.12 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Wed, 12 Jun 2013 16:50:12 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org Subject: Go patch committed: Implement Go 1.1 terminating statements Date: Wed, 12 Jun 2013 16:50:05 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux) MIME-Version: 1.0 X-Gm-Message-State: ALoCoQlrR3Zd4FZwW0vyf0lV2FEQrct425NTuAanYMixSZQ/R/y2t2BwHVJffEqix/ZpDgY7lhJBt75T0wZfU6Vks2IWXf/Zi3nxacxQu0gdBENsao/BKsXh/0h2HsfwNxeKiytlQOi1MlOoG5rPOgsua37iJqLugFo+vnUpzIXADwznC9u7+DJ05QSMlWwKGTZuZD9IskKvf8xCfFQ1e1H4pZjZG6CUKfar/ERz5p8IweTx8q3FUI8= X-Virus-Found: No The Go 1.1 release defines what it means for a function to have a terminating statement, and makes it an error for a function with return values to not have one. This patch, from Rémy Oudompheng, implements that for gccgo. Bootstrapped and ran testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.8 branch. Ian diff -r 8c0d464139d1 go/go.cc --- a/go/go.cc Fri Mar 01 11:26:17 2013 -0800 +++ b/go/go.cc Wed Jun 12 15:27:02 2013 -0700 @@ -44,7 +44,7 @@ GO_EXTERN_C void go_parse_input_files(const char** filenames, unsigned int filename_count, - bool only_check_syntax, bool require_return_statement) + bool only_check_syntax, bool) { go_assert(filename_count > 0); @@ -84,6 +84,9 @@ // Finalize method lists and build stub methods for named types. ::gogo->finalize_methods(); + // Check that functions have a terminating statement. + ::gogo->check_return_statements(); + // Now that we have seen all the names, lower the parse tree into a // form which is easier to use. ::gogo->lower_parse_tree(); @@ -104,10 +107,6 @@ if (only_check_syntax) return; - // Check that functions have return statements. - if (require_return_statement) - ::gogo->check_return_statements(); - // Export global identifiers as appropriate. ::gogo->do_exports(); diff -r 8c0d464139d1 go/statements.cc --- a/go/statements.cc Fri Mar 01 11:26:17 2013 -0800 +++ b/go/statements.cc Wed Jun 12 15:27:02 2013 -0700 @@ -1707,8 +1707,8 @@ this->expr_->discarding_value(); } -// An expression statement may fall through unless it is a call to a -// function which does not return. +// An expression statement is only a terminating statement if it is +// a call to panic. bool Expression_statement::do_may_fall_through() const @@ -1717,22 +1717,28 @@ if (call != NULL) { const Expression* fn = call->fn(); - const Func_expression* fe = fn->func_expression(); - if (fe != NULL) + // panic is still an unknown named object. + const Unknown_expression* ue = fn->unknown_expression(); + if (ue != NULL) { - const Named_object* no = fe->named_object(); - - Function_type* fntype; - if (no->is_function()) - fntype = no->func_value()->type(); - else if (no->is_function_declaration()) - fntype = no->func_declaration_value()->type(); - else - fntype = NULL; - - // The builtin function panic does not return. - if (fntype != NULL && fntype->is_builtin() && no->name() == "panic") - return false; + Named_object* no = ue->named_object(); + + if (no->is_unknown()) + no = no->unknown_value()->real_named_object(); + if (no != NULL) + { + Function_type* fntype; + if (no->is_function()) + fntype = no->func_value()->type(); + else if (no->is_function_declaration()) + fntype = no->func_declaration_value()->type(); + else + fntype = NULL; + + // The builtin function panic does not return. + if (fntype != NULL && fntype->is_builtin() && no->name() == "panic") + return false; + } } } return true; @@ -3700,9 +3706,6 @@ void do_check_types(Gogo*); - bool - do_may_fall_through() const; - Bstatement* do_get_backend(Translate_context*); @@ -3746,22 +3749,6 @@ this->set_is_error(); } -// Return whether this switch may fall through. - -bool -Constant_switch_statement::do_may_fall_through() const -{ - if (this->clauses_ == NULL) - return true; - - // If we have a break label, then some case needed it. That implies - // that the switch statement as a whole can fall through. - if (this->break_label_ != NULL) - return true; - - return this->clauses_->may_fall_through(); -} - // Convert to GENERIC. Bstatement* @@ -3911,6 +3898,22 @@ ast_dump_context->ostream() << std::endl; } +// Return whether this switch may fall through. + +bool +Switch_statement::do_may_fall_through() const +{ + if (this->clauses_ == NULL) + return true; + + // If we have a break label, then some case needed it. That implies + // that the switch statement as a whole can fall through. + if (this->break_label_ != NULL) + return true; + + return this->clauses_->may_fall_through(); +} + // Make a switch statement. Switch_statement* @@ -4050,6 +4053,17 @@ } } +// Return true if this type clause may fall through to the statements +// following the switch. + +bool +Type_case_clauses::Type_case_clause::may_fall_through() const +{ + if (this->statements_ == NULL) + return true; + return this->statements_->may_fall_through(); +} + // Dump the AST representation for a type case clause void @@ -4148,6 +4162,25 @@ NULL); } +// Return true if these clauses may fall through to the statements +// following the switch statement. + +bool +Type_case_clauses::may_fall_through() const +{ + bool found_default = false; + for (Type_clauses::const_iterator p = this->clauses_.begin(); + p != this->clauses_.end(); + ++p) + { + if (p->may_fall_through()) + return true; + if (p->is_default()) + found_default = true; + } + return !found_default; +} + // Dump the AST representation for case clauses (from a switch statement) void @@ -4237,6 +4270,22 @@ return Statement::make_block_statement(b, loc); } +// Return whether this switch may fall through. + +bool +Type_switch_statement::do_may_fall_through() const +{ + if (this->clauses_ == NULL) + return true; + + // If we have a break label, then some case needed it. That implies + // that the switch statement as a whole can fall through. + if (this->break_label_ != NULL) + return true; + + return this->clauses_->may_fall_through(); +} + // Return the break label for this type switch statement, creating it // if necessary. @@ -4954,6 +5003,19 @@ return Statement::make_block_statement(b, loc); } +// Whether the select statement itself may fall through to the following +// statement. + +bool +Select_statement::do_may_fall_through() const +{ + // A select statement is terminating if no break statement + // refers to it and all of its clauses are terminating. + if (this->break_label_ != NULL) + return true; + return this->clauses_->may_fall_through(); +} + // Return the backend representation for a select statement. Bstatement* @@ -5114,6 +5176,20 @@ this->continue_label_ = continue_label; } +// Whether the overall statement may fall through. + +bool +For_statement::do_may_fall_through() const +{ + // A for loop is terminating if it has no condition and + // no break statement. + if(this->cond_ != NULL) + return true; + if(this->break_label_ != NULL) + return true; + return false; +} + // Dump the AST representation for a for statement. void diff -r 8c0d464139d1 go/statements.h --- a/go/statements.h Fri Mar 01 11:26:17 2013 -0800 +++ b/go/statements.h Wed Jun 12 15:27:02 2013 -0700 @@ -894,8 +894,7 @@ { this->clauses_->check_types(); } bool - do_may_fall_through() const - { return this->clauses_->may_fall_through(); } + do_may_fall_through() const; Bstatement* do_get_backend(Translate_context*); @@ -1086,6 +1085,9 @@ Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); + bool + do_may_fall_through() const; + Bstatement* do_get_backend(Translate_context*) { go_unreachable(); } @@ -1399,6 +1401,9 @@ void do_dump_statement(Ast_dump_context*) const; + bool + do_may_fall_through() const; + private: // The value to switch on. This may be NULL. Expression* val_; @@ -1449,6 +1454,11 @@ lower(Type*, Block*, Temporary_statement* descriptor_temp, Unnamed_label* break_label) const; + // Return true if these clauses may fall through to the statements + // following the switch statement. + bool + may_fall_through() const; + // Dump the AST representation to a dump context. void dump_clauses(Ast_dump_context*) const; @@ -1493,6 +1503,12 @@ lower(Type*, Block*, Temporary_statement* descriptor_temp, Unnamed_label* break_label, Unnamed_label** stmts_label) const; + // Return true if this clause may fall through to execute the + // statements following the switch statement. This is not the + // same as whether this clause falls through to the next clause. + bool + may_fall_through() const; + // Dump the AST representation to a dump context. void dump_clause(Ast_dump_context*) const; @@ -1556,6 +1572,9 @@ void do_dump_statement(Ast_dump_context*) const; + bool + do_may_fall_through() const; + private: // The variable holding the value we are switching on. Named_object* var_;