This patch to the Go frontend by Than McIntosh improves type handling for string concat ops on constants. This resolves 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, ensure that the result has X's type, and disable folding if the both sides have a concrete type that does not match. This fixes https://golang.org/issue/31412. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline.
Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 270263) +++ gcc/go/gofrontend/MERGE (working copy) @@ -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: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 270263) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -1846,12 +1846,20 @@ String_expression::do_dump_expression(As 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, } // 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, && 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: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 270263) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -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 : 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&