From patchwork Thu Nov 11 20:22:22 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: 47503 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 184193857830 for ; Thu, 11 Nov 2021 20:23:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 184193857830 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1636662187; bh=VA05rQrmzA9AkStM4Lm5FUW9PxaUIjAu6ENSYCsbTuo=; h=Date:Subject:To:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=TNFe4qXaxrRsLb1eF4aKbISfqUlfGZ+28xeevQ1/ZQGw/0A0ibPBZdSAlxZgvxnRM YW4lYlxxaXZW8llYgPONy7pjFFftl4eSDO0mlycJDibDAiw7Ecm1b0BeWsmZ3gGoiO NiDVw33ZJ9/Ys1mgNgcwcD2f2MQn/75nKSvlBnDI= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-ed1-x534.google.com (mail-ed1-x534.google.com [IPv6:2a00:1450:4864:20::534]) by sourceware.org (Postfix) with ESMTPS id 9E6BE3857C7F for ; Thu, 11 Nov 2021 20:22:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9E6BE3857C7F Received: by mail-ed1-x534.google.com with SMTP id r12so28771191edt.6 for ; Thu, 11 Nov 2021 12:22:35 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=VA05rQrmzA9AkStM4Lm5FUW9PxaUIjAu6ENSYCsbTuo=; b=2F1OYlxKLKrkmgGDrxHeWK9VwtzhcWnhvjKjyBhWyW8zs18HxApvTvmCE9lH1y9yC6 /WXz42MggCsvfk5FPA9arqAD0npdGj3Vdq24iYZcDwbEstBw0iX2tyURezsEmfI/n8L7 k/pQ2EUdNnn6YLcMa0vB1afpVafRfDuK5wSdxhkk0WxWvhgFHmeUr3uu4K8CnDOPp72R rO83UuKNVUwDxcUzaQT2E1svX6DdZfUhTBJGH14s0dYNAvB1G6NjIMYRnZp+P3HTI8iK F49HO1y6B63jPoo36zNPkTfXgcfwxXjQnXYEphpyqQYulGXsyemFRCxzv6NnE4Fy7rLI KV5A== X-Gm-Message-State: AOAM532uPhO9LiNnbE03HkP3VAKvtJGXXWDSlI4xLDWTdRXNIm/N8Fve X2U52ls7/8gJJ/q4F92HY0SDceDwzosoyHcmiuikbiE5pYjzkg== X-Google-Smtp-Source: ABdhPJw1mZr75z6ip2W/CsANjtHz56DsRBB/fnocdRvmF+EBW73jZkW0mvP8g+XV9Zy8hFsKKFTwnbunaZr/AIv6NkY= X-Received: by 2002:a17:907:9723:: with SMTP id jg35mr13527869ejc.329.1636662154085; Thu, 11 Nov 2021 12:22:34 -0800 (PST) MIME-Version: 1.0 Date: Thu, 11 Nov 2021 12:22:22 -0800 Message-ID: Subject: Go patch committed: Traverse func subexprs when creating func descriptors To: gcc-patches , gofrontend-dev X-Spam-Status: No, score=-9.7 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.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This patch to the Go frontend fixes the Create_func_descriptors pass to traverse the subexpressions of the function in a Call_expression. There are no subexpressions in the normal case of calling a function a method directly, but there are subexpressions when in code like F().M() when F returns an interface type. Forgetting to traverse the function subexpressions was almost entirely hidden by the fact that we also created the necessary thunks in Bound_method_expression::do_flatten and Interface_field_reference_expression::do_get_backend. However, when the thunks were created there, they did not go through the order_evaluations pass. This almost always worked, but failed in the case in which the function being thunked returned multiple results, as order_evaluations takes the necessary step of moving the Call_expression into its own statement, and that would not happen when order_evaluations was not called. Avoid hiding errors like this by changing those methods to only lookup the previously created thunk, rather than creating it if it was not already created. The test case for this is https://golang.org/cl/363156. This fixes https://golang.org/issue/49512. Bootstrapped and ran Go tests on x86_64-pc-linux-gnu. Committed to mainline. Ian patch.txt 2b7d9dc49cbda7a8e98cfe0c59a8057b5c30907c diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index e7ff6705563..05e47ec3fa9 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -128ea3dce9b8753167f33d0a96bd093a6cbd58b8 +3e9f4ee16683883ccfb8661d99318c74bb7a4bef 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 ddb1d91f3e5..79702821336 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -7981,7 +7981,7 @@ Bound_method_expression::do_check_types(Gogo*) Bound_method_expression::Method_value_thunks Bound_method_expression::method_value_thunks; -// Find or create the thunk for METHOD. +// Find or create the thunk for FN. Named_object* Bound_method_expression::create_thunk(Gogo* gogo, const Method* method, @@ -8078,14 +8078,28 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method, gogo->add_statement(s); Block* b = gogo->finish_block(loc); gogo->add_block(b, loc); + + // This is called after lowering but before determine_types. gogo->lower_block(new_no, b); - gogo->flatten_block(new_no, b); + gogo->finish_function(loc); ins.first->second = new_no; return new_no; } +// Look up a thunk for FN. + +Named_object* +Bound_method_expression::lookup_thunk(Named_object* fn) +{ + Method_value_thunks::const_iterator p = + Bound_method_expression::method_value_thunks.find(fn); + if (p == Bound_method_expression::method_value_thunks.end()) + return NULL; + return p->second; +} + // Return an expression to check *REF for nil while dereferencing // according to FIELD_INDEXES. Update *REF to build up the field // reference. This is a static function so that we don't have to @@ -8129,10 +8143,11 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*, { Location loc = this->location(); - Named_object* thunk = Bound_method_expression::create_thunk(gogo, - this->method_, - this->function_); - if (thunk->is_erroneous()) + Named_object* thunk = Bound_method_expression::lookup_thunk(this->function_); + + // The thunk should have been created during the + // create_function_descriptors pass. + if (thunk == NULL || thunk->is_erroneous()) { go_assert(saw_errors()); return Expression::make_error(loc); @@ -14757,14 +14772,34 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo, gogo->add_statement(s); Block* b = gogo->finish_block(loc); gogo->add_block(b, loc); + + // This is called after lowering but before determine_types. gogo->lower_block(new_no, b); - gogo->flatten_block(new_no, b); + gogo->finish_function(loc); ins.first->second->push_back(std::make_pair(name, new_no)); return new_no; } +// Lookup a thunk to call method NAME on TYPE. + +Named_object* +Interface_field_reference_expression::lookup_thunk(Interface_type* type, + const std::string& name) +{ + Interface_method_thunks::const_iterator p = + Interface_field_reference_expression::interface_method_thunks.find(type); + if (p == Interface_field_reference_expression::interface_method_thunks.end()) + return NULL; + for (Method_thunks::const_iterator pm = p->second->begin(); + pm != p->second->end(); + ++pm) + if (pm->first == name) + return pm->second; + return NULL; +} + // Get the backend representation for a method value. Bexpression* @@ -14778,9 +14813,11 @@ Interface_field_reference_expression::do_get_backend(Translate_context* context) } Named_object* thunk = - Interface_field_reference_expression::create_thunk(context->gogo(), - type, this->name_); - if (thunk->is_erroneous()) + Interface_field_reference_expression::lookup_thunk(type, this->name_); + + // The thunk should have been created during the + // create_function_descriptors pass. + if (thunk == NULL || thunk->is_erroneous()) { go_assert(saw_errors()); return context->backend()->error_expression(); diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 93483544e46..92e8d8d96b4 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -3405,6 +3405,10 @@ class Bound_method_expression : public Expression static Named_object* create_thunk(Gogo*, const Method* method, Named_object* function); + // Look up a thunk. + static Named_object* + lookup_thunk(Named_object* function); + protected: int do_traverse(Traverse*); @@ -3578,6 +3582,10 @@ class Interface_field_reference_expression : public Expression static Named_object* create_thunk(Gogo*, Interface_type* type, const std::string& name); + // Look up a thunk. + static Named_object* + lookup_thunk(Interface_type* type, const std::string& name); + // Return an expression for the pointer to the function to call. Expression* get_function(); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 95b76bd317c..290d294e83b 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -3430,6 +3430,11 @@ Create_function_descriptors::expression(Expression** pexpr) if (args->traverse(this) == TRAVERSE_EXIT) return TRAVERSE_EXIT; } + + // Traverse the subexpressions of the function, if any. + if (fn->traverse_subexpressions(this) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + return TRAVERSE_SKIP_COMPONENTS; } }