compiler: improve type handling for string concat ops on constants

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
This commit is contained in:
Ian Lance Taylor 2019-04-13 01:03:55 +00:00
parent b15937488e
commit fdc59f56c1
3 changed files with 34 additions and 8 deletions

View 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.

View 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);

View 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&