compiler: avoid copy for string([]byte) conversion used in string concatenation

If a string([]byte) conversion is used immediately in a string
concatenation, we don't need to copy the backing store of the
byte slice, as the runtime function doesn't hold any reference
to it.

A test could be added in the GCC testsuite:

Index: gcc/testsuite/go.dg/concatstring.go
===================================================================
--- gcc/testsuite/go.dg/concatstring.go	(nonexistent)
+++ gcc/testsuite/go.dg/concatstring.go	(working copy)
@@ -0,0 +1,8 @@
+// { dg-do compile }
+// { dg-options "-fgo-debug-optimization" }
+
+package p
+
+func F(b []byte, x string) string {
+	return "hello " + string(b) + x // { dg-error "no copy string\\(\\\[\\\]byte\\)" }
+}

Change-Id: I1c2d13da6a30aca825aa42964a959452c7f50aaf
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/182437
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/go/expressions.cc b/go/expressions.cc
index 740daec..e5e6ba7 100644
--- a/go/expressions.cc
+++ b/go/expressions.cc
@@ -7408,6 +7408,26 @@
     return this;
   Location loc = this->location();
   Type* type = this->type();
+
+  // Mark string([]byte) operands to reuse the backing store.
+  // runtime.concatstrings does not keep the reference.
+  //
+  // Note: in the gc runtime, if all but one inputs are empty,
+  // concatstrings returns the only nonempty input without copy.
+  // So it is not safe to reuse the backing store if it is a
+  // string([]byte) conversion. So the gc compiler does the
+  // no-copy optimization only when there is at least one
+  // constant nonempty input. Currently the gccgo runtime
+  // doesn't do this, so we don't do the check.
+  for (Expression_list::iterator p = this->exprs_->begin();
+       p != this->exprs_->end();
+       ++p)
+    {
+      Type_conversion_expression* tce = (*p)->conversion_expression();
+      if (tce != NULL)
+        tce->set_no_copy(true);
+    }
+
   Expression* nil_arg = Expression::make_nil(loc);
   Expression* call;
   switch (this->exprs_->size())