From patchwork Wed Dec 28 03:46:25 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 133382 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 40323B6FB4 for ; Wed, 28 Dec 2011 14:46:47 +1100 (EST) Received: (qmail 6027 invoked by alias); 28 Dec 2011 03:46:44 -0000 Received: (qmail 6019 invoked by uid 22791); 28 Dec 2011 03:46:42 -0000 X-SWARE-Spam-Status: No, hits=-3.2 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from mail-iy0-f175.google.com (HELO mail-iy0-f175.google.com) (209.85.210.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 28 Dec 2011 03:46:29 +0000 Received: by iakh37 with SMTP id h37so18894472iak.20 for ; Tue, 27 Dec 2011 19:46:28 -0800 (PST) Received: by 10.50.219.234 with SMTP id pr10mr33703175igc.27.1325043988437; Tue, 27 Dec 2011 19:46:28 -0800 (PST) Received: by 10.50.219.234 with SMTP id pr10mr33703164igc.27.1325043988322; Tue, 27 Dec 2011 19:46:28 -0800 (PST) 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 f32sm94250956ibf.9.2011.12.27.19.46.26 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 27 Dec 2011 19:46:27 -0800 (PST) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: Go patch committed: No func, map or slice comparisons Date: Tue, 27 Dec 2011 19:46:25 -0800 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 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 language was changed to prohibit comparing values of func, map, or slice type, except for comparisons to nil. This patch implements that in the Go frontend. The patch includes some testsuite updates. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline. Ian Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 182696) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -1147,9 +1147,9 @@ class Binary_expression : public Express do_import(Import*); // Report an error if OP can not be applied to TYPE. Return whether - // it can. + // it can. OTYPE is the type of the other operand. static bool - check_operator_type(Operator op, Type* type, Location); + check_operator_type(Operator op, Type* type, Type* otype, Location); protected: int Index: gcc/go/gofrontend/types.cc =================================================================== --- gcc/go/gofrontend/types.cc (revision 182696) +++ gcc/go/gofrontend/types.cc (working copy) @@ -1235,8 +1235,6 @@ Type::type_functions(const char** hash_f case Type::TYPE_FLOAT: case Type::TYPE_COMPLEX: case Type::TYPE_POINTER: - case Type::TYPE_FUNCTION: - case Type::TYPE_MAP: case Type::TYPE_CHANNEL: *hash_fn = "__go_type_hash_identity"; *equal_fn = "__go_type_equal_identity"; @@ -1249,6 +1247,8 @@ Type::type_functions(const char** hash_f case Type::TYPE_STRUCT: case Type::TYPE_ARRAY: + case Type::TYPE_FUNCTION: + case Type::TYPE_MAP: // These types can not be hashed or compared. *hash_fn = "__go_type_hash_error"; *equal_fn = "__go_type_equal_error"; @@ -4731,7 +4731,9 @@ bool Map_type::do_verify() { if (this->key_type_->struct_type() != NULL - || this->key_type_->array_type() != NULL) + || this->key_type_->array_type() != NULL + || this->key_type_->function_type() != NULL + || this->key_type_->map_type() != NULL) { error_at(this->location_, "invalid map key type"); return false; Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 182696) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -6052,11 +6052,11 @@ Binary_expression::do_determine_type(con } // Report an error if the binary operator OP does not support TYPE. -// Return whether the operation is OK. This should not be used for -// shift. +// OTYPE is the type of the other operand. Return whether the +// operation is OK. This should not be used for shift. bool -Binary_expression::check_operator_type(Operator op, Type* type, +Binary_expression::check_operator_type(Operator op, Type* type, Type* otype, Location location) { switch (op) @@ -6092,6 +6092,16 @@ Binary_expression::check_operator_type(O "or function type")); return false; } + if ((type->is_slice_type() + || type->map_type() != NULL + || type->function_type() != NULL) + && !otype->is_nil_type()) + { + error_at(location, + ("slice, map, and function types may only " + "be compared to nil")); + return false; + } break; case OPERATOR_LT: @@ -6189,8 +6199,10 @@ Binary_expression::do_check_types(Gogo*) return; } if (!Binary_expression::check_operator_type(this->op_, left_type, + right_type, this->location()) || !Binary_expression::check_operator_type(this->op_, right_type, + left_type, this->location())) { this->set_is_error(); @@ -6205,6 +6217,7 @@ Binary_expression::do_check_types(Gogo*) return; } if (!Binary_expression::check_operator_type(this->op_, left_type, + right_type, this->location())) { this->set_is_error(); Index: gcc/testsuite/go.test/test/closure.go =================================================================== --- gcc/testsuite/go.test/test/closure.go (revision 182418) +++ gcc/testsuite/go.test/test/closure.go (working copy) @@ -76,7 +76,6 @@ func h() { func newfunc() func(int) int { return func(x int) int { return x } } - func main() { go f() check([]int{1, 4, 5, 4}) @@ -90,10 +89,6 @@ func main() { check([]int{100, 200, 101, 201, 500, 101, 201, 500}) x, y := newfunc(), newfunc() - if x == y { - println("newfunc returned same func") - panic("fail") - } if x(1) != 1 || y(2) != 2 { println("newfunc returned broken funcs") panic("fail") Index: gcc/testsuite/go.test/test/cmp1.go =================================================================== --- gcc/testsuite/go.test/test/cmp1.go (revision 182418) +++ gcc/testsuite/go.test/test/cmp1.go (working copy) @@ -1,130 +0,0 @@ -// $G $D/$F.go && $L $F.$A && ./$A.out - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import "unsafe" - -func use(bool) {} - -func stringptr(s string) uintptr { return *(*uintptr)(unsafe.Pointer(&s)) } - -func isfalse(b bool) { - if b { - // stack will explain where - panic("wanted false, got true") - } -} - -func istrue(b bool) { - if !b { - // stack will explain where - panic("wanted true, got false") - } -} - -type T *int - -func main() { - var a []int - var b map[string]int - - var c string = "hello" - var d string = "hel" // try to get different pointer - d = d + "lo" - if stringptr(c) == stringptr(d) { - panic("compiler too smart -- got same string") - } - - var e = make(chan int) - - var ia interface{} = a - var ib interface{} = b - var ic interface{} = c - var id interface{} = d - var ie interface{} = e - - // these comparisons are okay because - // string compare is okay and the others - // are comparisons where the types differ. - isfalse(ia == ib) - isfalse(ia == ic) - isfalse(ia == id) - isfalse(ib == ic) - isfalse(ib == id) - istrue(ic == id) - istrue(ie == ie) - - // these are okay because one side of the - // comparison need only be assignable to the other. - isfalse(a == ib) - isfalse(a == ic) - isfalse(a == id) - isfalse(b == ic) - isfalse(b == id) - istrue(c == id) - istrue(e == ie) - - isfalse(ia == b) - isfalse(ia == c) - isfalse(ia == d) - isfalse(ib == c) - isfalse(ib == d) - istrue(ic == d) - istrue(ie == e) - - // 6g used to let this go through as true. - var g uint64 = 123 - var h int64 = 123 - var ig interface{} = g - var ih interface{} = h - isfalse(ig == ih) - - // map of interface should use == on interface values, - // not memory. - // TODO: should m[c], m[d] be valid here? - var m = make(map[interface{}]int) - m[ic] = 1 - m[id] = 2 - if m[ic] != 2 { - println("m[ic] = ", m[ic]) - panic("bad m[ic]") - } - - // non-interface comparisons - { - c := make(chan int) - c1 := (<-chan int)(c) - c2 := (chan<- int)(c) - istrue(c == c1) - istrue(c == c2) - istrue(c1 == c) - istrue(c2 == c) - - d := make(chan int) - isfalse(c == d) - isfalse(d == c) - isfalse(d == c1) - isfalse(d == c2) - isfalse(c1 == d) - isfalse(c2 == d) - } - - // named types vs not - { - var x = new(int) - var y T - var z T = x - - isfalse(x == y) - istrue(x == z) - isfalse(y == z) - - isfalse(y == x) - istrue(z == x) - isfalse(z == y) - } -} Index: gcc/testsuite/go.test/test/typeswitch.go =================================================================== --- gcc/testsuite/go.test/test/typeswitch.go (revision 182418) +++ gcc/testsuite/go.test/test/typeswitch.go (working copy) @@ -82,9 +82,9 @@ func main() { case []int: assert(x[3] == 3 && i == Array, "array") case map[string]int: - assert(x == m && i == Map, "map") + assert(x != nil && i == Map, "map") case func(i int) interface{}: - assert(x == f && i == Func, "fun") + assert(x != nil && i == Func, "fun") default: assert(false, "unknown") } @@ -111,5 +111,4 @@ func main() { default: assert(false, "switch 4 unknown") } - } Index: gcc/testsuite/go.test/test/fixedbugs/bug285.go =================================================================== --- gcc/testsuite/go.test/test/fixedbugs/bug285.go (revision 182418) +++ gcc/testsuite/go.test/test/fixedbugs/bug285.go (working copy) @@ -45,20 +45,6 @@ func main() { mp[p] = 42 mp[&T{7}] = 42 - type F func(x int) - f := func(x int) {} - mf := make(map[F]int) - mf[nil] = 42 - mf[f] = 42 - mf[func(x int) {}] = 42 - - type M map[int]int - m := make(M) - mm := make(map[M]int) - mm[nil] = 42 - mm[m] = 42 - mm[make(M)] = 42 - type C chan int c := make(C) mc := make(map[C]int)