diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c index 2cd155d4d7..6603efe8d1 100644 --- a/src/cmd/gc/order.c +++ b/src/cmd/gc/order.c @@ -1031,6 +1031,18 @@ orderexpr(Node **np, Order *order) } break; + case OCMPSTR: + orderexpr(&n->left, order); + orderexpr(&n->right, order); + // Mark string(byteSlice) arguments to reuse byteSlice backing + // buffer during conversion. String comparison does not + // memorize the strings for later use, so it is safe. + if(n->left->op == OARRAYBYTESTR) + n->left->op = OARRAYBYTESTRTMP; + if(n->right->op == OARRAYBYTESTR) + n->right->op = OARRAYBYTESTRTMP; + break; + case OINDEXMAP: // key must be addressable orderexpr(&n->left, order); diff --git a/src/runtime/string.go b/src/runtime/string.go index 8aa0dd076d..6f7de4de1e 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -76,6 +76,7 @@ func slicebytetostringtmp(b []byte) string { // First such case is a m[string(k)] lookup where // m is a string-keyed map and k is a []byte. // Second such case is "<"+string(b)+">" concatenation where b is []byte. + // Third such case is string(b)=="foo" comparison where b is []byte. if raceenabled && len(b) > 0 { racereadrangepc(unsafe.Pointer(&b[0]), diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go index 1551ecc82b..03c8948467 100644 --- a/src/runtime/string_test.go +++ b/src/runtime/string_test.go @@ -158,3 +158,20 @@ func TestGostringnocopy(t *testing.T) { t.Errorf("want %d, got %d", max+9, newmax) } } + +func TestCompareTempString(t *testing.T) { + s := "foo" + b := []byte(s) + n := testing.AllocsPerRun(1000, func() { + if string(b) != s { + t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) + } + if string(b) == s { + } else { + t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) + } + }) + if n != 0 { + t.Fatalf("want 0 allocs, got %v", n) + } +}