compiler: improve type handling for string concat ops on constants
authorIan Lance Taylor <ian@gcc.gnu.org>
Sat, 13 Apr 2019 01:03:55 +0000 (01:03 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Sat, 13 Apr 2019 01:03:55 +0000 (01:03 +0000)
    Resolve a small problem with concatenation of string constants: in a
    string concat X + Y where X has named type and Y has abstract string
    type, insure that the result has X's type, and disable folding if the
    both sides have a concrete type that does not match.

    Fixes golang/go#31412.

    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/171797

From-SVN: r270336

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h

index 74e811b8a23ffc65c1956615aa6d96bca62336f6..381d791da8c163c07a2916d13612dfe823cdc699 100644 (file)
@@ -1,4 +1,4 @@
-8822487ed776d55eafed44de7d89ee54bbfbab47
+20010e494f46d8fd58cfd372093b059578d3379a
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 018fdbbec77bd656de8997e81894d5565798052b..6f9775dd5a20c7d48c8f1dbbe4ba9bb00921459a 100644 (file)
@@ -1846,12 +1846,20 @@ String_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
   String_expression::export_string(ast_dump_context, this);
 }
 
-// Make a string expression.
+// Make a string expression with abstract string type (common case).
 
 Expression*
 Expression::make_string(const std::string& val, Location location)
 {
-  return new String_expression(val, location);
+  return new String_expression(val, NULL, location);
+}
+
+// Make a string expression with a specific string type.
+
+Expression*
+Expression::make_string_typed(const std::string& val, Type* type, Location location)
+{
+  return new String_expression(val, type, location);
 }
 
 // An expression that evaluates to some characteristic of a string.
@@ -5485,7 +5493,16 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
   }
 
   // String constant expressions.
-  if (left->type()->is_string_type() && right->type()->is_string_type())
+  //
+  // Avoid constant folding here if the left and right types are incompatible
+  // (leave the operation intact so that the type checker can complain about it
+  // later on). If concatenating an abstract string with a named string type,
+  // result type needs to be of the named type (see issue 31412).
+  if (left->type()->is_string_type()
+      && right->type()->is_string_type()
+      && (left->type()->named_type() == NULL
+          || right->type()->named_type() == NULL
+          || left->type()->named_type() == right->type()->named_type()))
     {
       std::string left_string;
       std::string right_string;
@@ -5493,8 +5510,13 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
          && right->string_constant_value(&right_string))
        {
          if (op == OPERATOR_PLUS)
-           return Expression::make_string(left_string + right_string,
-                                          location);
+            {
+              Type* result_type = (left->type()->named_type() != NULL
+                                   ? left->type()
+                                   : right->type());
+              return Expression::make_string_typed(left_string + right_string,
+                                                   result_type, location);
+            }
          else if (is_comparison)
            {
              int cmp = left_string.compare(right_string);
index c521d9bf775cfb5a552209258dd99895f3893034..43aaccf9769eea113740e2a3ffac619cfbf992cd 100644 (file)
@@ -230,6 +230,10 @@ class Expression
   static Expression*
   make_string(const std::string&, Location);
 
+  // Make a constant string expression with a specific string subtype.
+  static Expression*
+  make_string_typed(const std::string&, Type*, Location);
+
   // Make an expression that evaluates to some characteristic of an string.
   // For simplicity, the enum values must match the field indexes in the
   // underlying struct.
@@ -1570,9 +1574,9 @@ class Set_and_use_temporary_expression : public Expression
 class String_expression : public Expression
 {
  public:
-  String_expression(const std::string& val, Location location)
+  String_expression(const std::string& val, Type* type, Location location)
     : Expression(EXPRESSION_STRING, location),
-      val_(val), type_(NULL)
+      val_(val), type_(type)
   { }
 
   const std::string&