From patchwork Thu Oct 24 19:16:16 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 286005 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 did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 231542C00E3 for ; Fri, 25 Oct 2013 06:16:32 +1100 (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=AKXUU0yrif5DsFgjJs6R1PKQdRPcqbzEWhc/dlV/peU9D9PN3kMat qChPKraxezk6rAejIAFfMQPT2VJgToaF+onJLWsC1/oktRl9EwEA/hWORjjfhHdI JAmOgEAS61LF+fju+MIUNQ1Pw2yAyyVeqodFaLYFaNsMu0XC7tpgl4= 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=ELuhWKgWMq4xmEx9LPqIpOh/PzA=; b=a8O5enK6VXTOUWi27a1e uuXmVarTtuRe3hqoAQI9m2n5QV9uPbJEgmJetBYdF9EuIN3wQ4N1XRd5Sh1i8o0/ oFeAiZUqfRXp8w5DnuGr01BtjpjfG3lz8aqg4CH/BSMPjT10o87G4QN+lwakwZpx unWbP0U5PtlkuLHe7oDZRc4= Received: (qmail 15656 invoked by alias); 24 Oct 2013 19:16:25 -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 15638 invoked by uid 89); 24 Oct 2013 19:16:24 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.2 required=5.0 tests=AWL, BAYES_05, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, SPF_PASS, T_TVD_MIME_NO_HEADERS autolearn=ham version=3.3.2 X-HELO: mail-pa0-f47.google.com Received: from mail-pa0-f47.google.com (HELO mail-pa0-f47.google.com) (209.85.220.47) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Thu, 24 Oct 2013 19:16:21 +0000 Received: by mail-pa0-f47.google.com with SMTP id lf10so2923683pab.34 for ; Thu, 24 Oct 2013 12:16:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:user-agent :mime-version:content-type; bh=YixeQqPrFGfm2pf2z9ZFAFOh84OUB3eTJjPIyh3i0GA=; b=Sg05DFMDa0nNZgmaOqb1+MEdV7cmA6PVkrKCHqH0ZJzThTNxnb3nSsGZIymxtG6cF3 7aiPy23MRNW/tYJx4rz4jn8DRkvQsOC3OrvK0ePbmzX6wCPwyTN0DIvnfiZOv/Gu220e cjtEW1wvLnLn4AodSiuPe/yy5txjC7staSVm0kYBst0XjWdUA+a8VdD+fwkqKC+RWdQ+ rqXEx+LSoztFXtId/MQ6UMutG02vz9Jmlejrka4GBpMEWkmuTaRAlQKkRo0PXaSiPNhW P914wy0HNqE/d1FBpnlmnp6Cl9EVWYTf2/rIO797urHj7aA+VmB663+KEEmu61Z29v9f mkHA== X-Gm-Message-State: ALoCoQl6q3oUcN0fZ8CMFxJS2nYgAS/STdKUKCWDV554LYFEjvrUsFG+o1MPVFnLsaFbTwbbcck/MpYvTIHNI97Xkhamgaez7FIw79qr79qPVbK1JbqDjwlKvOGBC1zPlAD0rKhSA0kzL/y2t6M8AEX0zPh5ySsr5UGAY1QOVeX4q3+AOgNekvX+vPrsrPMx/tfRse2VWpsrYF+2LW4kyxK34gFmmuYIJw== X-Received: by 10.67.21.130 with SMTP id hk2mr4897737pad.76.1382642179720; Thu, 24 Oct 2013 12:16:19 -0700 (PDT) Received: from iant-glaptop.roam.corp.google.com.google.com ([172.19.241.10]) by mx.google.com with ESMTPSA id dq3sm4323410pbc.35.2013.10.24.12.16.18 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Thu, 24 Oct 2013 12:16:19 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: Go patch committed: Support three-index slices Date: Thu, 24 Oct 2013 12:16:16 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux) MIME-Version: 1.0 X-IsSubscribed: yes This patch from Chris Manghane adds support for three-index slices to the Go frontend. Three-index slices are new language feature in Go 1.2 (http://tip.golang.org/doc/go1.2#three_index). Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline. Ian diff -r 886731829abf go/expressions.cc --- a/go/expressions.cc Wed Oct 23 16:56:39 2013 -0700 +++ b/go/expressions.cc Thu Oct 24 12:12:12 2013 -0700 @@ -10235,7 +10235,9 @@ if (Expression::traverse(&this->left_, traverse) == TRAVERSE_EXIT || Expression::traverse(&this->start_, traverse) == TRAVERSE_EXIT || (this->end_ != NULL - && Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT)) + && Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT) + || (this->cap_ != NULL + && Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT)) return TRAVERSE_EXIT; return TRAVERSE_CONTINUE; } @@ -10250,6 +10252,7 @@ Expression* left = this->left_; Expression* start = this->start_; Expression* end = this->end_; + Expression* cap = this->cap_; Type* type = left->type(); if (type->is_error()) @@ -10260,20 +10263,27 @@ return Expression::make_error(location); } else if (type->array_type() != NULL) - return Expression::make_array_index(left, start, end, location); + return Expression::make_array_index(left, start, end, cap, location); else if (type->points_to() != NULL && type->points_to()->array_type() != NULL && !type->points_to()->is_slice_type()) { Expression* deref = Expression::make_unary(OPERATOR_MULT, left, location); - return Expression::make_array_index(deref, start, end, location); + return Expression::make_array_index(deref, start, end, cap, location); } else if (type->is_string_type()) - return Expression::make_string_index(left, start, end, location); + { + if (cap != NULL) + { + error_at(location, "invalid 3-index slice of string"); + return Expression::make_error(location); + } + return Expression::make_string_index(left, start, end, location); + } else if (type->map_type() != NULL) { - if (end != NULL) + if (end != NULL || cap != NULL) { error_at(location, "invalid slice of map"); return Expression::make_error(location); @@ -10292,14 +10302,15 @@ } } -// Write an indexed expression (expr[expr:expr] or expr[expr]) to a -// dump context +// Write an indexed expression +// (expr[expr:expr:expr], expr[expr:expr] or expr[expr]) to a dump context. void Index_expression::dump_index_expression(Ast_dump_context* ast_dump_context, const Expression* expr, const Expression* start, - const Expression* end) + const Expression* end, + const Expression* cap) { expr->dump_expression(ast_dump_context); ast_dump_context->ostream() << "["; @@ -10309,6 +10320,11 @@ ast_dump_context->ostream() << ":"; end->dump_expression(ast_dump_context); } + if (cap != NULL) + { + ast_dump_context->ostream() << ":"; + cap->dump_expression(ast_dump_context); + } ast_dump_context->ostream() << "]"; } @@ -10319,16 +10335,16 @@ const { Index_expression::dump_index_expression(ast_dump_context, this->left_, - this->start_, this->end_); + this->start_, this->end_, this->cap_); } // Make an index expression. Expression* Expression::make_index(Expression* left, Expression* start, Expression* end, - Location location) -{ - return new Index_expression(left, start, end, location); + Expression* cap, Location location) +{ + return new Index_expression(left, start, end, cap, location); } // An array index. This is used for both indexing and slicing. @@ -10337,9 +10353,9 @@ { public: Array_index_expression(Expression* array, Expression* start, - Expression* end, Location location) + Expression* end, Expression* cap, Location location) : Expression(EXPRESSION_ARRAY_INDEX, location), - array_(array), start_(start), end_(end), type_(NULL) + array_(array), start_(start), end_(end), cap_(cap), type_(NULL) { } protected: @@ -10363,6 +10379,9 @@ (this->end_ == NULL ? NULL : this->end_->copy()), + (this->cap_ == NULL + ? NULL + : this->cap_->copy()), this->location()); } @@ -10394,6 +10413,9 @@ // The end index of a slice. This may be NULL for a simple array // index, or it may be a nil expression for the length of the array. Expression* end_; + // The capacity argument of a slice. This may be NULL for an array index or + // slice. + Expression* cap_; // The type of the expression. Type* type_; }; @@ -10412,6 +10434,11 @@ if (Expression::traverse(&this->end_, traverse) == TRAVERSE_EXIT) return TRAVERSE_EXIT; } + if (this->cap_ != NULL) + { + if (Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } return TRAVERSE_CONTINUE; } @@ -10451,6 +10478,8 @@ this->start_->determine_type_no_context(); if (this->end_ != NULL) this->end_->determine_type_no_context(); + if (this->cap_ != NULL) + this->cap_->determine_type_no_context(); } // Check types of an array index. @@ -10473,6 +10502,14 @@ && (!this->end_->numeric_constant_value(&nc) || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) this->report_error(_("slice end must be integer")); + if (this->cap_ != NULL + && this->cap_->type()->integer_type() == NULL + && !this->cap_->type()->is_error() + && !this->cap_->is_nil_expression() + && !this->cap_->is_error_expression() + && (!this->cap_->numeric_constant_value(&nc) + || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) + this->report_error(_("slice capacity must be integer")); Array_type* array_type = this->array_->type()->array_type(); if (array_type == NULL) @@ -10510,8 +10547,10 @@ { Numeric_constant enc; mpz_t eval; + bool eval_valid = false; if (this->end_->numeric_constant_value(&enc) && enc.to_int(&eval)) { + eval_valid = true; if (mpz_sgn(eval) < 0 || mpz_sizeinbase(eval, 2) >= int_bits || (lval_valid && mpz_cmp(eval, lval) > 0)) @@ -10521,8 +10560,37 @@ } else if (ival_valid && mpz_cmp(ival, eval) > 0) this->report_error(_("inverted slice range")); - mpz_clear(eval); - } + } + + Numeric_constant cnc; + mpz_t cval; + if (this->cap_ != NULL + && this->cap_->numeric_constant_value(&cnc) && cnc.to_int(&cval)) + { + if (mpz_sgn(cval) < 0 + || mpz_sizeinbase(cval, 2) >= int_bits + || (lval_valid && mpz_cmp(cval, lval) > 0)) + { + error_at(this->cap_->location(), "array index out of bounds"); + this->set_is_error(); + } + else if (ival_valid && mpz_cmp(ival, cval) > 0) + { + error_at(this->cap_->location(), + "invalid slice index: capacity less than start"); + this->set_is_error(); + } + else if (eval_valid && mpz_cmp(eval, cval) > 0) + { + error_at(this->cap_->location(), + "invalid slice index: capacity less than length"); + this->set_is_error(); + } + mpz_clear(cval); + } + + if (eval_valid) + mpz_clear(eval); } if (ival_valid) mpz_clear(ival); @@ -10602,9 +10670,17 @@ capacity_tree = save_expr(capacity_tree); } + tree cap_arg = capacity_tree; + if (this->cap_ != NULL) + { + cap_arg = this->cap_->get_tree(context); + if (cap_arg == error_mark_node) + return error_mark_node; + } + tree length_type = (length_tree != NULL_TREE ? TREE_TYPE(length_tree) - : TREE_TYPE(capacity_tree)); + : TREE_TYPE(cap_arg)); tree bad_index = boolean_false_node; @@ -10676,6 +10752,29 @@ // Array slice. + if (this->cap_ != NULL) + { + if (!DECL_P(cap_arg)) + cap_arg = save_expr(cap_arg); + if (!INTEGRAL_TYPE_P(TREE_TYPE(cap_arg))) + cap_arg = convert_to_integer(length_type, cap_arg); + + bad_index = Expression::check_bounds(cap_arg, length_type, bad_index, + loc); + cap_arg = fold_convert_loc(loc.gcc_location(), length_type, cap_arg); + + tree bad_cap = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, + boolean_type_node, + fold_build2_loc(loc.gcc_location(), + LT_EXPR, boolean_type_node, + cap_arg, start_tree), + fold_build2_loc(loc.gcc_location(), + GT_EXPR, boolean_type_node, + cap_arg, capacity_tree)); + bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, + boolean_type_node, bad_index, bad_cap); + } + tree end_tree; if (this->end_->is_nil_expression()) end_tree = length_tree; @@ -10701,11 +10800,12 @@ end_tree, start_tree), fold_build2_loc(loc.gcc_location(), GT_EXPR, boolean_type_node, - end_tree, capacity_tree)); + end_tree, cap_arg)); bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, boolean_type_node, bad_index, bad_end); } + Type* element_type = array_type->element_type(); tree element_type_tree = type_to_tree(element_type->get_backend(gogo)); if (element_type_tree == error_mark_node) @@ -10729,8 +10829,7 @@ length_type, end_tree, start_tree); tree result_capacity_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR, - length_type, capacity_tree, - start_tree); + length_type, cap_arg, start_tree); tree struct_tree = type_to_tree(this->type()->get_backend(gogo)); go_assert(TREE_CODE(struct_tree) == RECORD_TYPE); @@ -10780,16 +10879,17 @@ const { Index_expression::dump_index_expression(ast_dump_context, this->array_, - this->start_, this->end_); -} - -// Make an array index expression. END may be NULL. + this->start_, this->end_, this->cap_); +} + +// Make an array index expression. END and CAP may be NULL. Expression* Expression::make_array_index(Expression* array, Expression* start, - Expression* end, Location location) -{ - return new Array_index_expression(array, start, end, location); + Expression* end, Expression* cap, + Location location) +{ + return new Array_index_expression(array, start, end, cap, location); } // A string index. This is used for both indexing and slicing. @@ -11067,8 +11167,8 @@ String_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { - Index_expression::dump_index_expression(ast_dump_context, this->string_, - this->start_, this->end_); + Index_expression::dump_index_expression(ast_dump_context, this->string_, + this->start_, this->end_, NULL); } // Make a string index expression. END may be NULL. @@ -11295,8 +11395,8 @@ Map_index_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { - Index_expression::dump_index_expression(ast_dump_context, - this->map_, this->index_, NULL); + Index_expression::dump_index_expression(ast_dump_context, this->map_, + this->index_, NULL, NULL); } // Make a map index expression. diff -r 886731829abf go/expressions.h --- a/go/expressions.h Wed Oct 23 16:56:39 2013 -0700 +++ b/go/expressions.h Thu Oct 24 12:12:12 2013 -0700 @@ -232,19 +232,21 @@ Named_object* function, Location); // Make an index or slice expression. This is a parser expression - // which represents LEFT[START:END]. END may be NULL, meaning an - // index rather than a slice. At parse time we may not know the - // type of LEFT. After parsing this is lowered to an array index, a - // string index, or a map index. + // which represents LEFT[START:END:CAP]. END may be NULL, meaning an + // index rather than a slice. CAP may be NULL, meaning we use the default + // capacity of LEFT. At parse time we may not know the type of LEFT. + // After parsing this is lowered to an array index, a string index, + // or a map index. static Expression* make_index(Expression* left, Expression* start, Expression* end, - Location); + Expression* cap, Location); // Make an array index expression. END may be NULL, in which case - // this is an lvalue. + // this is an lvalue. CAP may be NULL, in which case it defaults + // to cap(ARRAY). static Expression* make_array_index(Expression* array, Expression* start, Expression* end, - Location); + Expression* cap, Location); // Make a string index expression. END may be NULL. This is never // an lvalue. @@ -1672,9 +1674,9 @@ { public: Index_expression(Expression* left, Expression* start, Expression* end, - Location location) + Expression* cap, Location location) : Parser_expression(EXPRESSION_INDEX, location), - left_(left), start_(start), end_(end), is_lvalue_(false) + left_(left), start_(start), end_(end), cap_(cap), is_lvalue_(false) { } // Record that this expression is an lvalue. @@ -1683,10 +1685,11 @@ { this->is_lvalue_ = true; } // Dump an index expression, i.e. an expression of the form - // expr[expr] or expr[expr:expr], to a dump context. + // expr[expr], expr[expr:expr], or expr[expr:expr:expr] to a dump context. static void dump_index_expression(Ast_dump_context*, const Expression* expr, - const Expression* start, const Expression* end); + const Expression* start, const Expression* end, + const Expression* cap); protected: int @@ -1702,6 +1705,9 @@ (this->end_ == NULL ? NULL : this->end_->copy()), + (this->cap_ == NULL + ? NULL + : this->cap_->copy()), this->location()); } @@ -1723,6 +1729,10 @@ // The second index. This is NULL for an index, non-NULL for a // slice. Expression* end_; + // The capacity argument. This is NULL for indices and slices that use the + // default capacity, non-NULL for indices and slices that specify the + // capacity. + Expression* cap_; // Whether this is being used as an l-value. We set this during the // parse because map index expressions need to know. bool is_lvalue_; diff -r 886731829abf go/parse.cc --- a/go/parse.cc Wed Oct 23 16:56:39 2013 -0700 +++ b/go/parse.cc Thu Oct 24 12:12:12 2013 -0700 @@ -3152,7 +3152,7 @@ } // Index = "[" Expression "]" . -// Slice = "[" Expression ":" [ Expression ] "]" . +// Slice = "[" Expression ":" [ Expression ] [ ":" Expression ] "]" . Expression* Parse::index(Expression* expr) @@ -3178,14 +3178,31 @@ // We use nil to indicate a missing high expression. if (this->advance_token()->is_op(OPERATOR_RSQUARE)) end = Expression::make_nil(this->location()); + else if (this->peek_token()->is_op(OPERATOR_COLON)) + { + error_at(this->location(), "middle index required in 3-index slice"); + end = Expression::make_error(this->location()); + } else end = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); } + + Expression* cap = NULL; + if (this->peek_token()->is_op(OPERATOR_COLON)) + { + if (this->advance_token()->is_op(OPERATOR_RSQUARE)) + { + error_at(this->location(), "final index required in 3-index slice"); + cap = Expression::make_error(this->location()); + } + else + cap = this->expression(PRECEDENCE_NORMAL, false, true, NULL, NULL); + } if (!this->peek_token()->is_op(OPERATOR_RSQUARE)) error_at(this->location(), "missing %<]%>"); else this->advance_token(); - return Expression::make_index(expr, start, end, location); + return Expression::make_index(expr, start, end, cap, location); } // Call = "(" [ ArgumentList [ "," ] ] ")" . diff -r 886731829abf go/statements.cc --- a/go/statements.cc Wed Oct 23 16:56:39 2013 -0700 +++ b/go/statements.cc Thu Oct 24 12:12:12 2013 -0700 @@ -5540,7 +5540,7 @@ ref = this->make_range_ref(range_object, range_temp, loc); Expression* ref2 = Expression::make_temporary_reference(index_temp, loc); - Expression* index = Expression::make_index(ref, ref2, NULL, loc); + Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc); tref = Expression::make_temporary_reference(value_temp, loc); tref->set_is_lvalue(); @@ -5641,7 +5641,7 @@ ref = Expression::make_temporary_reference(for_temp, loc); Expression* ref2 = Expression::make_temporary_reference(index_temp, loc); - Expression* index = Expression::make_index(ref, ref2, NULL, loc); + Expression* index = Expression::make_index(ref, ref2, NULL, NULL, loc); tref = Expression::make_temporary_reference(value_temp, loc); tref->set_is_lvalue(); @@ -5849,7 +5849,7 @@ Expression* zexpr = Expression::make_integer(&zval, NULL, loc); mpz_clear(zval); - Expression* index = Expression::make_index(ref, zexpr, NULL, loc); + Expression* index = Expression::make_index(ref, zexpr, NULL, NULL, loc); Expression* ne = Expression::make_binary(OPERATOR_NOTEQ, index, Expression::make_nil(loc), diff -r 886731829abf go/types.cc --- a/go/types.cc Wed Oct 23 16:56:39 2013 -0700 +++ b/go/types.cc Thu Oct 24 12:12:12 2013 -0700 @@ -5645,12 +5645,12 @@ Expression* e1 = Expression::make_temporary_reference(p1, bloc); e1 = Expression::make_unary(OPERATOR_MULT, e1, bloc); ref = Expression::make_temporary_reference(index, bloc); - e1 = Expression::make_array_index(e1, ref, NULL, bloc); + e1 = Expression::make_array_index(e1, ref, NULL, NULL, bloc); Expression* e2 = Expression::make_temporary_reference(p2, bloc); e2 = Expression::make_unary(OPERATOR_MULT, e2, bloc); ref = Expression::make_temporary_reference(index, bloc); - e2 = Expression::make_array_index(e2, ref, NULL, bloc); + e2 = Expression::make_array_index(e2, ref, NULL, NULL, bloc); Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, e1, e2, bloc);