From patchwork Thu Mar 11 23:48:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 1451618 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=KzvHFUeM; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DxQd60BqKz9sVt for ; Fri, 12 Mar 2021 10:48:40 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5CB7A3950C71; Thu, 11 Mar 2021 23:48:37 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5CB7A3950C71 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1615506517; bh=UEhl78o06K1hXwC2yatkp+LCSA9O3+ZoQO5HBP9Eq3s=; h=Date:Subject:To:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=KzvHFUeMuEDzOoVeQDVVqFgvJTyTxRRPSikMldF8bO9xptN99aUw2br4V8EC4av06 rIo8b/wO7O9kZuEAYMX5L+yP4lMuZCP3sWdOJ8ia5TMO94BiJhXF1It0O3eFSIdWDd TtZIgzqg5F5SXGoXc+Ui3Rd24bCMLKXk0gLmkZLw= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-ej1-x631.google.com (mail-ej1-x631.google.com [IPv6:2a00:1450:4864:20::631]) by sourceware.org (Postfix) with ESMTPS id 050263894435 for ; Thu, 11 Mar 2021 23:48:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 050263894435 Received: by mail-ej1-x631.google.com with SMTP id c10so49780924ejx.9 for ; Thu, 11 Mar 2021 15:48:32 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=UEhl78o06K1hXwC2yatkp+LCSA9O3+ZoQO5HBP9Eq3s=; b=jwK/hSCTvhJH9h9Wn2lQJQ4jr5QNFvbMJF0j31SuzckehksHKHUBs92w/0uzuBL1/m sFHHcSxIXt5zhmUfdbdPfPA2mH+0n6pfuJ3UkUqDG97q6ShTXmTc3OhqM5JmVGEUTwER rMOryDuVOaIkQI3jH/t+/+u0IeMC2fQ9YcLy1EFJ43jitau4VwaVNjTTfYcZhzzew7I7 YYyEW8drMZTNW9Y2YE2dbb3MXSuwyS6X12sesyqAV/uxzr2zP6VKmtNvgWcBSk4JtdaD ySj7olgNOie/PHjRCNpQ3MITUJ5vM59r3rnSAjgMkG2EnlN29pdbkPDeO5kBQCO5OpNM pfNQ== X-Gm-Message-State: AOAM531BMydS9s0gOz5O2WTmT5env2ghmbc0B0Q1EAz7LSSV1vxfqvqT eympx321ULq0Qa6s08aOx1U6QvnFdIl5WpmoAiU+wsulKchswg== X-Google-Smtp-Source: ABdhPJzPheHxLYXEtekcMEuWeOpE2IaU4oLwCyNV902Pi5lqg6HO+aOjnUai3zcBlX8RU9OU1VDUAOoZwTPhx9voTNg= X-Received: by 2002:a17:906:c1ca:: with SMTP id bw10mr5650842ejb.510.1615506511894; Thu, 11 Mar 2021 15:48:31 -0800 (PST) MIME-Version: 1.0 Date: Thu, 11 Mar 2021 15:48:21 -0800 Message-ID: Subject: Go patch committed: create temporaries for heap variables To: gcc-patches , gofrontend-dev X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Ian Lance Taylor via Gcc-patches From: Ian Lance Taylor Reply-To: Ian Lance Taylor Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" The Go frontend generally doesn't create a temporary for an expression that is a variable, because it's normally valid to simply reload thevalue from the variable. However, if the variable is in the heap, then loading the value is a pointer indirection. The process of creating GCC IR can cause the variable load and the pointer indirection to be split, such that the second evaluation only does the pointer indirection. If there are conditionals in between the two uses, this can cause the second use to load the pointer from an uninitialized register. This patch avoids this by introducing a new Expression method that returns whether it is safe to evaluate an expression multiple times, and use it everywhere. The test case is https://golang.org/cl/300789. This fixes https://golang.org/issue/44383. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian b7781971f555a2b752ef1afd02732493bef1dec6 diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 5b45f03a26e..58c881a7872 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -93380a9126e76b71fa208e62c31c7914084c0e37 +bf35249a7c752836741b1cab43a312f87916fcb0 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 17b4cfd2c19..101cbe7ac31 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -526,7 +526,7 @@ Expression::convert_interface_to_interface(Type *lhs_type, Expression* rhs, // method table. // We are going to evaluate RHS multiple times. - go_assert(rhs->is_variable()); + go_assert(rhs->is_multi_eval_safe()); // Get the type descriptor for the right hand side. This will be // NULL for a nil interface. @@ -569,7 +569,7 @@ Expression::convert_interface_to_type(Gogo* gogo, Type *lhs_type, Expression* rh Location location) { // We are going to evaluate RHS multiple times. - go_assert(rhs->is_variable()); + go_assert(rhs->is_multi_eval_safe()); // Build an expression to check that the type is valid. It will // panic with an appropriate runtime type error if the type is not @@ -707,8 +707,8 @@ Expression::check_bounds(Expression* val, Operator op, Expression* bound, Statement_inserter* inserter, Location loc) { - go_assert(val->is_variable() || val->is_constant()); - go_assert(bound->is_variable() || bound->is_constant()); + go_assert(val->is_multi_eval_safe()); + go_assert(bound->is_multi_eval_safe()); Type* int_type = Type::lookup_integer_type("int"); int int_type_size = int_type->integer_type()->bits(); @@ -3976,7 +3976,7 @@ Type_conversion_expression::do_flatten(Gogo*, Named_object*, if (((this->type()->is_string_type() && this->expr_->type()->is_slice_type()) || this->expr_->type()->interface_type() != NULL) - && !this->expr_->is_variable()) + && !this->expr_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_, this->location()); @@ -4264,7 +4264,7 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Array_type* a = expr_type->array_type(); Type* e = a->element_type()->forwarded(); go_assert(e->integer_type() != NULL); - go_assert(this->expr_->is_variable()); + go_assert(this->expr_->is_multi_eval_safe()); Expression* buf; if (this->no_escape_ && !this->no_copy_) @@ -4711,7 +4711,7 @@ Unary_expression::do_flatten(Gogo* gogo, Named_object*, Location location = this->location(); if (this->op_ == OPERATOR_MULT - && !this->expr_->is_variable()) + && !this->expr_->is_multi_eval_safe()) { go_assert(this->expr_->type()->points_to() != NULL); switch (this->requires_nil_check(gogo)) @@ -4731,7 +4731,7 @@ Unary_expression::do_flatten(Gogo* gogo, Named_object*, } } - if (this->create_temp_ && !this->expr_->is_variable()) + if (this->create_temp_ && !this->expr_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_, location); @@ -5326,7 +5326,7 @@ Unary_expression::do_get_backend(Translate_context* context) bexpr = gogo->backend()->var_expression(decl, loc); } - go_assert(!this->create_temp_ || this->expr_->is_variable()); + go_assert(!this->create_temp_ || this->expr_->is_multi_eval_safe()); ret = gogo->backend()->address_expression(bexpr, loc); break; @@ -5347,7 +5347,7 @@ Unary_expression::do_get_backend(Translate_context* context) } case NIL_CHECK_NEEDED: { - go_assert(this->expr_->is_variable()); + go_assert(this->expr_->is_multi_eval_safe()); // If we're nil-checking the result of a set-and-use-temporary // expression, then pick out the target temp and use that @@ -6496,13 +6496,13 @@ Binary_expression::do_flatten(Gogo* gogo, Named_object*, && (gogo->check_divide_by_zero() || gogo->check_divide_overflow())) || is_string_op) { - if (!this->left_->is_variable() && !this->left_->is_constant()) + if (!this->left_->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, this->left_, loc); inserter->insert(temp); this->left_ = Expression::make_temporary_reference(temp, loc); } - if (!this->right_->is_variable() && !this->right_->is_constant()) + if (!this->right_->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, this->right_, loc); @@ -7478,8 +7478,8 @@ Expression::comparison(Translate_context* context, Type* result_type, if (left_type->is_string_type() && right_type->is_string_type()) { - go_assert(left->is_variable() || left->is_constant()); - go_assert(right->is_variable() || right->is_constant()); + go_assert(left->is_multi_eval_safe()); + go_assert(right->is_multi_eval_safe()); if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ) { @@ -8078,7 +8078,7 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*, // we are going to do nil checks below, but it's easy enough to // always do it. Expression* expr = this->expr_; - if (!expr->is_variable()) + if (!expr->is_multi_eval_safe()) { Temporary_statement* etemp = Statement::make_temporary(NULL, expr, loc); inserter->insert(etemp); @@ -8419,7 +8419,7 @@ Builtin_call_expression::do_lower(Gogo*, Named_object* function, pa != this->args()->end(); ++pa) { - if (!(*pa)->is_variable() && !(*pa)->is_constant()) + if (!(*pa)->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, *pa, loc); @@ -8470,7 +8470,7 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, Expression* zero = Expression::make_integer_ul(0, NULL, loc); *pa = Expression::make_slice_value(at, nil, zero, zero, loc); } - if (!(*pa)->is_variable()) + if (!(*pa)->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, *pa, loc); @@ -8484,8 +8484,8 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, go_assert(args != NULL && args->size() == 2); Expression* arg1 = args->front(); Expression* arg2 = args->back(); - go_assert(arg1->is_variable()); - go_assert(arg2->is_variable()); + go_assert(arg1->is_multi_eval_safe()); + go_assert(arg2->is_multi_eval_safe()); bool arg2_is_string = arg2->type()->is_string_type(); Expression* ret; @@ -8573,7 +8573,8 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, pa != this->args()->end(); ++pa) { - if (!(*pa)->is_variable() && (*pa)->type()->interface_type() != NULL) + if (!(*pa)->is_multi_eval_safe() + && (*pa)->type()->interface_type() != NULL) { Temporary_statement* temp = Statement::make_temporary(NULL, *pa, loc); @@ -8587,7 +8588,7 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function, case BUILTIN_CAP: { Expression_list::iterator pa = this->args()->begin(); - if (!(*pa)->is_variable() + if (!(*pa)->is_multi_eval_safe() && ((*pa)->type()->map_type() != NULL || (*pa)->type()->channel_type() != NULL)) { @@ -9024,7 +9025,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, Expression_list::const_iterator pa = args->begin(); for (++pa; pa != args->end(); ++pa) { - if ((*pa)->is_variable()) + if ((*pa)->is_multi_eval_safe()) add->push_back(*pa); else { @@ -11235,7 +11236,7 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, { Location loc = (*pa)->location(); Expression* arg = *pa; - if (!arg->is_variable()) + if (!arg->is_multi_eval_safe()) { Temporary_statement *temp = Statement::make_temporary(NULL, arg, loc); @@ -11457,7 +11458,7 @@ Call_expression::intrinsify(Gogo* gogo, && this->args_ != NULL && this->args_->size() == 1) { Expression* arg = this->args_->front(); - if (!arg->is_variable()) + if (!arg->is_multi_eval_safe()) { Temporary_statement* ts = Statement::make_temporary(uint32_type, arg, loc); inserter->insert(ts); @@ -11476,7 +11477,7 @@ Call_expression::intrinsify(Gogo* gogo, && this->args_ != NULL && this->args_->size() == 1) { Expression* arg = this->args_->front(); - if (!arg->is_variable()) + if (!arg->is_multi_eval_safe()) { Temporary_statement* ts = Statement::make_temporary(uint64_type, arg, loc); inserter->insert(ts); @@ -11526,7 +11527,7 @@ Call_expression::intrinsify(Gogo* gogo, && this->args_ != NULL && this->args_->size() == 1) { Expression* arg = this->args_->front(); - if (!arg->is_variable()) + if (!arg->is_multi_eval_safe()) { Temporary_statement* ts = Statement::make_temporary(uint32_type, arg, loc); inserter->insert(ts); @@ -11549,7 +11550,7 @@ Call_expression::intrinsify(Gogo* gogo, && this->args_ != NULL && this->args_->size() == 1) { Expression* arg = this->args_->front(); - if (!arg->is_variable()) + if (!arg->is_multi_eval_safe()) { Temporary_statement* ts = Statement::make_temporary(uint64_type, arg, loc); inserter->insert(ts); @@ -13087,14 +13088,14 @@ Array_index_expression::do_flatten(Gogo* gogo, Named_object*, } Temporary_statement* temp; - if (array_type->is_slice_type() && !array->is_variable()) + if (array_type->is_slice_type() && !array->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, array, loc); inserter->insert(temp); this->array_ = Expression::make_temporary_reference(temp, loc); array = this->array_; } - if (!start->is_variable() && !start->is_constant()) + if (!start->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, start, loc); inserter->insert(temp); @@ -13103,15 +13104,14 @@ Array_index_expression::do_flatten(Gogo* gogo, Named_object*, } if (end != NULL && !end->is_nil_expression() - && !end->is_variable() - && !end->is_constant()) + && !end->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, end, loc); inserter->insert(temp); this->end_ = Expression::make_temporary_reference(temp, loc); end = this->end_; } - if (cap != NULL && !cap->is_variable() && !cap->is_constant()) + if (cap != NULL && !cap->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, cap, loc); inserter->insert(temp); @@ -13270,7 +13270,8 @@ Array_index_expression::do_get_backend(Translate_context* context) go_assert(this->array_->type()->is_error()); return context->backend()->error_expression(); } - go_assert(!array_type->is_slice_type() || this->array_->is_variable()); + go_assert(!array_type->is_slice_type() + || this->array_->is_multi_eval_safe()); Location loc = this->location(); Gogo* gogo = context->gogo(); @@ -13484,14 +13485,14 @@ String_index_expression::do_flatten(Gogo*, Named_object*, } Temporary_statement* temp; - if (!string->is_variable()) + if (!string->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, string, loc); inserter->insert(temp); this->string_ = Expression::make_temporary_reference(temp, loc); string = this->string_; } - if (!start->is_variable()) + if (!start->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, start, loc); inserter->insert(temp); @@ -13500,7 +13501,7 @@ String_index_expression::do_flatten(Gogo*, Named_object*, } if (end != NULL && !end->is_nil_expression() - && !end->is_variable()) + && !end->is_multi_eval_safe()) { temp = Statement::make_temporary(NULL, end, loc); inserter->insert(temp); @@ -13659,8 +13660,8 @@ String_index_expression::do_get_backend(Translate_context* context) return context->backend()->error_expression(); } - go_assert(this->string_->is_variable()); - go_assert(this->start_->is_variable()); + go_assert(this->string_->is_multi_eval_safe()); + go_assert(this->start_->is_multi_eval_safe()); Expression* start = Expression::make_cast(int_type, this->start_, loc); Bfunction* bfn = context->function()->func_value()->get_decl(); @@ -13685,7 +13686,7 @@ String_index_expression::do_get_backend(Translate_context* context) end = length; else { - go_assert(this->end_->is_variable()); + go_assert(this->end_->is_multi_eval_safe()); end = Expression::make_cast(int_type, this->end_, loc); } @@ -13815,7 +13816,7 @@ Map_index_expression::do_flatten(Gogo* gogo, Named_object*, NULL)) { if (this->index_->type()->interface_type() != NULL - && !this->index_->is_variable()) + && !this->index_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->index_, loc); @@ -13826,7 +13827,7 @@ Map_index_expression::do_flatten(Gogo* gogo, Named_object*, this->index_, loc); } - if (!this->index_->is_variable()) + if (!this->index_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->index_, loc); @@ -13839,7 +13840,7 @@ Map_index_expression::do_flatten(Gogo* gogo, Named_object*, if (this->value_pointer_->is_error_expression() || this->value_pointer_->type()->is_error_type()) return Expression::make_error(loc); - if (!this->value_pointer_->is_variable()) + if (!this->value_pointer_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->value_pointer_, loc); @@ -13923,7 +13924,7 @@ Map_index_expression::do_get_backend(Translate_context* context) } go_assert(this->value_pointer_ != NULL - && this->value_pointer_->is_variable()); + && this->value_pointer_->is_multi_eval_safe()); Expression* val = Expression::make_dereference(this->value_pointer_, NIL_CHECK_NOT_NEEDED, @@ -14268,7 +14269,7 @@ Interface_field_reference_expression::do_flatten(Gogo*, Named_object*, return Expression::make_error(this->location()); } - if (!this->expr_->is_variable()) + if (!this->expr_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_, this->location()); @@ -15165,7 +15166,7 @@ Struct_construction_expression::do_flatten(Gogo*, Named_object*, go_assert(saw_errors()); return Expression::make_error(loc); } - if (!(*pv)->is_variable()) + if (!(*pv)->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, *pv, loc); @@ -15471,7 +15472,7 @@ Array_construction_expression::do_flatten(Gogo*, Named_object*, go_assert(saw_errors()); return Expression::make_error(loc); } - if (!(*pv)->is_variable()) + if (!(*pv)->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, *pv, loc); @@ -15914,7 +15915,8 @@ Map_construction_expression::do_flatten(Gogo* gogo, Named_object*, go_assert(saw_errors()); return Expression::make_error(loc); } - if (key->type()->interface_type() != NULL && !key->is_variable()) + if (key->type()->interface_type() != NULL + && !key->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, key, loc); @@ -15930,7 +15932,8 @@ Map_construction_expression::do_flatten(Gogo* gogo, Named_object*, go_assert(saw_errors()); return Expression::make_error(loc); } - if (val->type()->interface_type() != NULL && !val->is_variable()) + if (val->type()->interface_type() != NULL + && !val->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, val, loc); @@ -17037,6 +17040,41 @@ Expression::is_local_variable() const || (no->is_variable() && !no->var_value()->is_global())); } +// Return true if multiple evaluations are OK. + +bool +Expression::is_multi_eval_safe() +{ + switch (this->classification_) + { + case EXPRESSION_VAR_REFERENCE: + { + // A variable is a simple reference if not stored in the heap. + const Named_object* no = this->var_expression()->named_object(); + if (no->is_variable()) + return !no->var_value()->is_in_heap(); + else if (no->is_result_variable()) + return !no->result_var_value()->is_in_heap(); + else + go_unreachable(); + } + + case EXPRESSION_TEMPORARY_REFERENCE: + return true; + + default: + break; + } + + if (!this->is_constant()) + return false; + + // Only numeric and boolean constants are really multi-evaluation + // safe. We don't want multiple copies of string constants. + Type* type = this->type(); + return type->is_numeric_type() || type->is_boolean_type(); +} + const Named_object* Expression::named_constant() const { @@ -17070,7 +17108,7 @@ Type_guard_expression::do_flatten(Gogo*, Named_object*, return Expression::make_error(this->location()); } - if (!this->expr_->is_variable()) + if (!this->expr_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_, this->location()); diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 712f6870211..e3747cc65d7 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -916,6 +916,11 @@ class Expression bool is_local_variable() const; + // Return true if multiple evaluations of this expression are OK. + // This is true for simple variable references and constants. + bool + is_multi_eval_safe(); + // Return true if two expressions refer to the same variable or // struct field. static bool diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 9d4150eff7c..93b54fd8c11 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -7579,7 +7579,7 @@ Variable::flatten_init_expression(Gogo* gogo, Named_object* function, Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && this->init_->type()->interface_type() != NULL - && !this->init_->is_variable()) + && !this->init_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->init_, this->location_); diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index da0e0843a73..7ad7339bda8 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -588,7 +588,7 @@ Temporary_statement::do_flatten(Gogo*, Named_object*, Block*, Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && this->init_->type()->interface_type() != NULL - && !this->init_->is_variable()) + && !this->init_->is_multi_eval_safe()) { Temporary_statement *temp = Statement::make_temporary(NULL, this->init_, this->location()); @@ -1125,7 +1125,7 @@ Assignment_statement::do_flatten(Gogo*, Named_object*, Block*, Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && this->rhs_->type()->interface_type() != NULL - && !this->rhs_->is_variable()) + && !this->rhs_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->rhs_, this->location()); @@ -5116,7 +5116,7 @@ Send_statement::do_flatten(Gogo*, Named_object*, Block*, Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && this->val_->type()->interface_type() != NULL - && !this->val_->is_variable()) + && !this->val_->is_multi_eval_safe()) { Temporary_statement* temp = Statement::make_temporary(NULL, this->val_, this->location()); diff --git a/gcc/go/gofrontend/wb.cc b/gcc/go/gofrontend/wb.cc index ac1f0a1eff9..104c5db0b9b 100644 --- a/gcc/go/gofrontend/wb.cc +++ b/gcc/go/gofrontend/wb.cc @@ -883,7 +883,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, Type::COMPARE_ERRORS | Type::COMPARE_TAGS, NULL) && rhs->type()->interface_type() != NULL - && !rhs->is_variable()) + && !rhs->is_multi_eval_safe()) { // May need a temporary for interface conversion. Temporary_statement* temp = Statement::make_temporary(NULL, rhs, loc); @@ -892,7 +892,7 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, } rhs = Expression::convert_for_assignment(this, type, rhs, loc); Temporary_statement* rhs_temp = NULL; - if (!rhs->is_variable() && !rhs->is_constant()) + if (!rhs->is_multi_eval_safe()) { rhs_temp = Statement::make_temporary(NULL, rhs, loc); inserter->insert(rhs_temp);