This patch from Chris Manghane fixes escape analysis to correctly handle calls to interface conversion functions that return multiple results. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 225715) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -a5122ab435cf40c22b110487eb5f189ee28e77f4 +1b3d945d201bcb1238f15ef154c6e4671e4c6f5c The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/escape.cc =================================================================== --- gcc/go/gofrontend/escape.cc (revision 225715) +++ gcc/go/gofrontend/escape.cc (working copy) @@ -547,6 +547,41 @@ Build_connection_graphs::resolve_var_ref expr = expr->type_guard_expression()->expr(); break; + case Expression::EXPRESSION_UNSAFE_CONVERSION: + { + Expression* e = expr->unsafe_conversion_expression()->expr(); + if (e->call_result_expression() != NULL + && e->call_result_expression()->index() == 0) + { + // a, ok := p.(T) gets lowered into a call to one of the interface + // to type conversion functions instead of a type guard expression. + // We only want to make a connection between a and p, the bool + // result should not escape because p escapes. + e = e->call_result_expression()->call(); + + Named_object* fn = + e->call_expression()->fn()->func_expression()->named_object(); + std::string fn_name = fn->name(); + if (fn->package() == NULL + && fn->is_function_declaration() + && !fn->func_declaration_value()->asm_name().empty()) + { + if (fn_name == "ifaceI2E2" + || fn_name == "ifaceI2I2") + e = e->call_expression()->args()->at(0); + else if (fn_name == "ifaceE2I2" + || fn_name == "ifaceI2I2" + || fn_name == "ifaceE2T2P" + || fn_name == "ifaceI2T2P" + || fn_name == "ifaceE2T2" + || fn_name == "ifaceI2T2") + e = e->call_expression()->args()->at(1); + } + } + expr = e; + } + break; + default: done = true; break; Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 225715) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -3391,52 +3391,7 @@ Expression::make_cast(Type* type, Expres return new Type_conversion_expression(type, val, location); } -// An unsafe type conversion, used to pass values to builtin functions. - -class Unsafe_type_conversion_expression : public Expression -{ - public: - Unsafe_type_conversion_expression(Type* type, Expression* expr, - Location location) - : Expression(EXPRESSION_UNSAFE_CONVERSION, location), - type_(type), expr_(expr) - { } - - protected: - int - do_traverse(Traverse* traverse); - - bool - do_is_immutable() const; - - Type* - do_type() - { return this->type_; } - - void - do_determine_type(const Type_context*) - { this->expr_->determine_type_no_context(); } - - Expression* - do_copy() - { - return new Unsafe_type_conversion_expression(this->type_, - this->expr_->copy(), - this->location()); - } - - Bexpression* - do_get_backend(Translate_context*); - - void - do_dump_expression(Ast_dump_context*) const; - - private: - // The type to convert to. - Type* type_; - // The expression to convert. - Expression* expr_; -}; +// Class Unsafe_type_conversion_expression. // Traversal. Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 225715) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -32,6 +32,7 @@ class Temporary_reference_expression; class Set_and_use_temporary_expression; class String_expression; class Type_conversion_expression; +class Unsafe_type_conversion_expression; class Unary_expression; class Binary_expression; class Call_expression; @@ -571,6 +572,15 @@ class Expression conversion_expression() { return this->convert<Type_conversion_expression, EXPRESSION_CONVERSION>(); } + // If this is an unsafe conversion expression, return the + // Unsafe_type_conversion_expression structure. Otherwise, return NULL. + Unsafe_type_conversion_expression* + unsafe_conversion_expression() + { + return this->convert<Unsafe_type_conversion_expression, + EXPRESSION_UNSAFE_CONVERSION>(); + } + // Return whether this is the expression nil. bool is_nil_expression() const @@ -1505,6 +1515,57 @@ class Type_conversion_expression : publi bool may_convert_function_types_; }; +// An unsafe type conversion, used to pass values to builtin functions. + +class Unsafe_type_conversion_expression : public Expression +{ + public: + Unsafe_type_conversion_expression(Type* type, Expression* expr, + Location location) + : Expression(EXPRESSION_UNSAFE_CONVERSION, location), + type_(type), expr_(expr) + { } + + Expression* + expr() const + { return this->expr_; } + + protected: + int + do_traverse(Traverse* traverse); + + bool + do_is_immutable() const; + + Type* + do_type() + { return this->type_; } + + void + do_determine_type(const Type_context*) + { this->expr_->determine_type_no_context(); } + + Expression* + do_copy() + { + return new Unsafe_type_conversion_expression(this->type_, + this->expr_->copy(), + this->location()); + } + + Bexpression* + do_get_backend(Translate_context*); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The type to convert to. + Type* type_; + // The expression to convert. + Expression* expr_; +}; + // A Unary expression. class Unary_expression : public Expression @@ -2024,6 +2085,10 @@ class Call_result_expression : public Ex call() const { return this->call_; } + unsigned int + index() const + { return this->index_; } + protected: int do_traverse(Traverse*);