From patchwork Wed Oct 3 05:03:35 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: 188707 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 599EF2C009D for ; Wed, 3 Oct 2012 15:03:55 +1000 (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=1349845436; 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=ylARGh1 EZmkVhBvzun/202uQM4s=; b=Sw73mzXLSGYYd4vKR3yKD8MI48Tk2L/SuUe5pMm pm3t9fd0kHNEUY/HOSn2yN4AkASsQqrLANCPYTCyS+bk+YbvClZlol31Sm6yg9ox W/73u0PwKXYbabWxkGW3vKIeL4+weO0D6LkcIkWozyFMKHjTH4QTQNVv/zuTsH1m TBgU= 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=kr89eJ12QKc9GMt9qJgy1VBVXNXZ1hgmhLEAdN5gq8hIxZzYycuGK0nkLSiyJr P/gZhZThuzHkXoWb2SLBuE22AfmPq0nBDXQL1kdHkgCpG5blGF5wwH8gd5MwNnyz Ir+W032tlFDMeHhnKcraaUB/2lwjtYn13ZksspOlkcQzQ=; Received: (qmail 6780 invoked by alias); 3 Oct 2012 05:03:50 -0000 Received: (qmail 6762 invoked by uid 22791); 3 Oct 2012 05:03:48 -0000 X-SWARE-Spam-Status: No, hits=-5.4 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE, RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from mail-pb0-f47.google.com (HELO mail-pb0-f47.google.com) (209.85.160.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 03 Oct 2012 05:03:40 +0000 Received: by pbbro12 with SMTP id ro12so9913247pbb.20 for ; Tue, 02 Oct 2012 22:03:40 -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=N0F3vQnjyavG6XL5i0jmmcZEcK2w2gTT9hNPvAy3f8o=; b=Ud2lAc/9kbHZIuG8Owlobah0gn01aTw8u3cBk5UgRJ78dxHeOYrjUL1tQXa69mvXft f/zVTsHL+ZlPlWUCQ6ZRH60A47hfBMkFNUawEk3nExSyWD2oJDQWB4q6mcRlPx5irIZh 4ERbBaV3PUqIkt7CCNVpsx3/dBoyIp4zw792k+NrS/KeH+lXZgbjsR20D5m5JQ4h3pom 63hGWn/JuZBvH1GNJmvAH6wnzSRqBk721wjLxlnR7MR3H0Wkp2N9hnAyhfqR3VbZ2gG2 zwdLTWkViztfp/509nnUAnk9IOaBtgJMJ60RcVFWi9rQFAkHEsGezm3NSovdkz7j3n7U ddVA== Received: by 10.68.221.168 with SMTP id qf8mr9986865pbc.37.1349240619978; Tue, 02 Oct 2012 22:03:39 -0700 (PDT) Received: from coign.google.com (adsl-71-133-8-30.dsl.pltn13.pacbell.net. [71.133.8.30]) by mx.google.com with ESMTPS id o1sm1856224pax.21.2012.10.02.22.03.37 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 02 Oct 2012 22:03:38 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: Go patch committed: Fix a, b, c := b, a, 1 when a and b already exist Date: Tue, 02 Oct 2012 22:03:35 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-Gm-Message-State: ALoCoQmR06lb6ttGVSQWE46Oc0gSHoBPERo6/pkP56sd9BLrfH/rfH6CDU+ZguGi9EyikbM1+uUbliaOH7HYtPEToJHOyYwJDgB7gViVNA8yhUxMAMvHu6BVl1EfN50q6meQGQCHxJjTmZROoroIK/HNI5lu1dzM7HV/jE2Xc6BmTis6/mAoam6YZS2Sw53vV/5ea4asWP+7 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 The Go := operator can declare new variables while also referring to existing variables. The Go frontend was miscompiling a case like a, b, c := b, a, 1 where a and b already exist. It was assigning to a and then using the new value of to assign to b. This patch fixes this bug. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.7 branch. Ian diff -r b66fde007054 go/parse.cc --- a/go/parse.cc Tue Oct 02 16:49:04 2012 -0700 +++ b/go/parse.cc Tue Oct 02 21:50:56 2012 -0700 @@ -1631,12 +1631,16 @@ // Note that INIT was already parsed with the old name bindings, so // we don't have to worry that it will accidentally refer to the - // newly declared variables. + // newly declared variables. But we do have to worry about a mix of + // newly declared variables and old variables if the old variables + // appear in the initializations. Expression_list::const_iterator pexpr; if (init != NULL) pexpr = init->begin(); bool any_new = false; + Expression_list* vars = new Expression_list(); + Expression_list* vals = new Expression_list(); for (Typed_identifier_list::const_iterator p = til->begin(); p != til->end(); ++p) @@ -1644,7 +1648,7 @@ if (init != NULL) go_assert(pexpr != init->end()); this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq, - false, &any_new); + false, &any_new, vars, vals); if (init != NULL) ++pexpr; } @@ -1652,6 +1656,7 @@ go_assert(pexpr == init->end()); if (is_coloneq && !any_new) error_at(location, "variables redeclared but no variable is new"); + this->finish_init_vars(vars, vals, location); } // See if we need to initialize a list of variables from a function @@ -1674,13 +1679,15 @@ Named_object* first_var = NULL; unsigned int index = 0; bool any_new = false; + Expression_list* ivars = new Expression_list(); + Expression_list* ivals = new Expression_list(); for (Typed_identifier_list::const_iterator pv = vars->begin(); pv != vars->end(); ++pv, ++index) { Expression* init = Expression::make_call_result(call, index); Named_object* no = this->init_var(*pv, type, init, is_coloneq, false, - &any_new); + &any_new, ivars, ivals); if (this->gogo_->in_global_scope() && no->is_variable()) { @@ -1700,6 +1707,8 @@ if (is_coloneq && !any_new) error_at(location, "variables redeclared but no variable is new"); + this->finish_init_vars(ivars, ivals, location); + return true; } @@ -1725,7 +1734,7 @@ Typed_identifier_list::const_iterator p = vars->begin(); Expression* init = type == NULL ? index : NULL; Named_object* val_no = this->init_var(*p, type, init, is_coloneq, - type == NULL, &any_new); + type == NULL, &any_new, NULL, NULL); if (type == NULL && any_new && val_no->is_variable()) val_no->var_value()->set_type_from_init_tuple(); Expression* val_var = Expression::make_var_reference(val_no, location); @@ -1735,7 +1744,7 @@ if (var_type == NULL) var_type = Type::lookup_bool_type(); Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false, - &any_new); + &any_new, NULL, NULL); Expression* present_var = Expression::make_var_reference(no, location); if (is_coloneq && !any_new) @@ -1790,7 +1799,7 @@ Typed_identifier_list::const_iterator p = vars->begin(); Expression* init = type == NULL ? receive : NULL; Named_object* val_no = this->init_var(*p, type, init, is_coloneq, - type == NULL, &any_new); + type == NULL, &any_new, NULL, NULL); if (type == NULL && any_new && val_no->is_variable()) val_no->var_value()->set_type_from_init_tuple(); Expression* val_var = Expression::make_var_reference(val_no, location); @@ -1800,7 +1809,7 @@ if (var_type == NULL) var_type = Type::lookup_bool_type(); Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false, - &any_new); + &any_new, NULL, NULL); Expression* received_var = Expression::make_var_reference(no, location); if (is_coloneq && !any_new) @@ -1857,7 +1866,7 @@ if (var_type == NULL) var_type = type_guard->type(); Named_object* val_no = this->init_var(*p, var_type, NULL, is_coloneq, false, - &any_new); + &any_new, NULL, NULL); Expression* val_var = Expression::make_var_reference(val_no, location); ++p; @@ -1865,7 +1874,7 @@ if (var_type == NULL) var_type = Type::lookup_bool_type(); Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false, - &any_new); + &any_new, NULL, NULL); Expression* ok_var = Expression::make_var_reference(no, location); Expression* texpr = type_guard->expr(); @@ -1904,7 +1913,8 @@ Named_object* Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init, - bool is_coloneq, bool type_from_init, bool* is_new) + bool is_coloneq, bool type_from_init, bool* is_new, + Expression_list* vars, Expression_list* vals) { Location location = tid.location(); @@ -1946,9 +1956,9 @@ // like v, ok := x.(int). if (!type_from_init && init != NULL) { - Expression *v = Expression::make_var_reference(no, location); - Statement *s = Statement::make_assignment(v, init, location); - this->gogo_->add_statement(s); + go_assert(vars != NULL && vals != NULL); + vars->push_back(Expression::make_var_reference(no, location)); + vals->push_back(init); } return no; } @@ -1983,6 +1993,36 @@ return this->gogo_->add_variable(buf, var); } +// Finish the variable initialization by executing any assignments to +// existing variables when using :=. These must be done as a tuple +// assignment in case of something like n, a, b := 1, b, a. + +void +Parse::finish_init_vars(Expression_list* vars, Expression_list* vals, + Location location) +{ + if (vars->empty()) + { + delete vars; + delete vals; + } + else if (vars->size() == 1) + { + go_assert(!this->gogo_->in_global_scope()); + this->gogo_->add_statement(Statement::make_assignment(vars->front(), + vals->front(), + location)); + delete vars; + delete vals; + } + else + { + go_assert(!this->gogo_->in_global_scope()); + this->gogo_->add_statement(Statement::make_tuple_assignment(vars, vals, + location)); + } +} + // SimpleVarDecl = identifier ":=" Expression . // We've already seen the identifier. @@ -5113,7 +5153,8 @@ bool any_new = false; const Typed_identifier* pti = &til->front(); - Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new); + Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new, + NULL, NULL); if (any_new && no->is_variable()) no->var_value()->set_type_from_range_index(); p_range_clause->index = Expression::make_var_reference(no, location); @@ -5124,7 +5165,7 @@ { pti = &til->back(); bool is_new = false; - no = this->init_var(*pti, NULL, expr, true, true, &is_new); + no = this->init_var(*pti, NULL, expr, true, true, &is_new, NULL, NULL); if (is_new && no->is_variable()) no->var_value()->set_type_from_range_value(); if (is_new) diff -r b66fde007054 go/parse.h --- a/go/parse.h Tue Oct 02 16:49:04 2012 -0700 +++ b/go/parse.h Tue Oct 02 21:50:56 2012 -0700 @@ -206,8 +206,11 @@ Expression*, bool is_coloneq, Location); Named_object* init_var(const Typed_identifier&, Type*, Expression*, - bool is_coloneq, bool type_from_init, bool* is_new); + bool is_coloneq, bool type_from_init, bool* is_new, + Expression_list* vars, Expression_list* vals); Named_object* create_dummy_global(Type*, Expression*, Location); + void finish_init_vars(Expression_list* vars, Expression_list* vals, + Location); void simple_var_decl_or_assignment(const std::string&, Location, bool may_be_composite_lit, Range_clause*, Type_switch*);