From patchwork Tue Aug 31 01:26:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1522378 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+incoming=patchwork.ozlabs.org@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=WT6zHakN; 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 4Gz8gm3wkLz9sT6 for ; Tue, 31 Aug 2021 11:27:29 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0AE463858401 for ; Tue, 31 Aug 2021 01:27:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0AE463858401 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1630373247; bh=4JyWlTMW34V6KfUsBTc7bNO8IMD4W1jbDD0TzxT73QU=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=WT6zHakNJjSHnI+ZJoWPeo2eLQduTWKSh3DZfAl0iNvedVnaiImXlV2AtJZAFX+T8 2Rwx8WB3Tt0Z+095yEIAKGKs85Py5gtj+eUyNUC0+kumeUw352XIYLjqrkNtEPccpf VLMcpZnIMqEBed7wSNTahnFwzSlZyjsl81bwmRJk= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id D66E03858D34 for ; Tue, 31 Aug 2021 01:26:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D66E03858D34 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-434-IWS253TyO0OQzz7-yFe_eg-1; Mon, 30 Aug 2021 21:26:43 -0400 X-MC-Unique: IWS253TyO0OQzz7-yFe_eg-1 Received: by mail-qt1-f198.google.com with SMTP id z16-20020ac86b90000000b0029eec160182so1803412qts.9 for ; Mon, 30 Aug 2021 18:26:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=4JyWlTMW34V6KfUsBTc7bNO8IMD4W1jbDD0TzxT73QU=; b=QpZ9PknoC320TS1kN9OjV2hY7DiQIPFD6baeBN5W+ODMvrYTJussav5gEnko1/LkWc mZkCBU1iKwPDMk9OCIyPcSTNnt1mPPiIIvv1gTU554xUkNYZ5+Zg69+Cfq3dv0tIltEd vmvBNtjMWe0xiXNp0DKf2qJSVTd+2CBzSIrCctfGCAAgLg3cBxyaHDk67likm00UsrOo J6dJsrY7yib12TRVNcP1mWrg1C4zRwow8YouWiX0T0GGWZrjR0OgglffFzwqxeEWi2b7 FxfW7MaYHQngarTLvBwnZw8iHonlg9eJKGQaXyKfE0tWQfK0ckzEIVZ8yYW3UE/aqTTj pZhQ== X-Gm-Message-State: AOAM5308BMZU+kiLA2gyJPAuBbqN78n7TAn74+JTOLvwrGXn4LUNSOco AOt5hfMpSE0nNc7iHPo6hXzE5F/Somm9nctgKIrBRdZpyWUorUt7eM3DoxCcodRNapxhYyL3c/5 2S9daHPzbOZ1qQ2Ss5QCTN1osUuzrSrm+1FbUEYc7KDfscbQUQ0WDKl+enK4PgxGM5mc= X-Received: by 2002:a05:620a:111b:: with SMTP id o27mr588236qkk.76.1630373202474; Mon, 30 Aug 2021 18:26:42 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxFgjwBo7uTQiNcN9tHEn5YdTOLVxL+0yhsKZ8WDmFd7A/Z6f6jx1IISIheK6UtWu8n5tojQA== X-Received: by 2002:a05:620a:111b:: with SMTP id o27mr588212qkk.76.1630373202086; Mon, 30 Aug 2021 18:26:42 -0700 (PDT) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id h13sm12264274qkk.67.2021.08.30.18.26.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 30 Aug 2021 18:26:41 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: check arity before deduction w/ explicit targs [PR12672] Date: Mon, 30 Aug 2021 21:26:38 -0400 Message-Id: <20210831012638.3293672-1-ppalka@redhat.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-16.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, 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: Patrick Palka via Gcc-patches From: Patrick Palka Reply-To: Patrick Palka Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" During overload resolution, when the arity of a function template clearly disagrees with the arity of the call, no specialization of the function template could yield a viable candidate. The deduction routine type_unification_real already notices this situation, but not before it substitutes explicit template arguments into the template, a step which could induce a hard error. Although it's necessary to perform this substitution first in order to check arity perfectly (since the substitution can e.g. expand a non-trailing parameter pack), in most cases we can determine ahead of time whether there's an arity disagreement without needing to perform deduction. To that end, this patch implements an (approximate) arity check in add_template_candidate_real that guards actual deduction. It's enabled only when there are explicit template arguments since that's when deduction can force otherwise avoidable template instantiations. (I experimented with enabling it unconditionally as an optimization and saw some compile-time improvements of about 5% but also some regressions by about the same magnitude, so kept it conditional.) In passing, this adds a least_p parameter to arity_rejection for sake of consistent diagnostics with unify_arity. A couple of testcases needed to be adjusted so that deduction continues to occur as intended after this change. Except in unify6.C, where we were expecting foo to be ill-formed due to substitution yielding a function type with an added 'const', but I think this is permitted by [dcl.fct]/7, so I changed the test accordingly. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? PR c++/12672 gcc/cp/ChangeLog: * call.c (rejection_reason::call_varargs_p): Rename this previously unused member to ... (rejection_reason::least_p): ... this. (arity_rejection): Add least_p parameter. (add_template_candidate_real): When there are explicit template arguments, check that the arity of the call agrees with the arity of the function before attempting deduction. (print_arity_information): Add least_p parameter. (print_z_candidate): Adjust call to print_arity_information. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/decltype29.C: Adjust. * g++.dg/template/error56.C: Adjust. * g++.old-deja/g++.pt/unify6.C: Adjust. * g++.dg/template/explicit-args6.C: New test. --- gcc/cp/call.c | 67 ++++++++++++++++--- gcc/testsuite/g++.dg/cpp0x/decltype29.C | 4 +- gcc/testsuite/g++.dg/template/error56.C | 4 +- .../g++.dg/template/explicit-args6.C | 33 +++++++++ gcc/testsuite/g++.old-deja/g++.pt/unify6.C | 4 +- 5 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/explicit-args6.C diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e4df72ec1a3..80e6121ce44 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -455,8 +455,8 @@ struct rejection_reason { int expected; /* The actual number of arguments in the call. */ int actual; - /* Whether the call was a varargs call. */ - bool call_varargs_p; + /* Whether EXPECTED should be treated as a lower bound. */ + bool least_p; } arity; /* Information about an argument conversion mismatch. */ struct conversion_info conversion; @@ -628,12 +628,13 @@ alloc_rejection (enum rejection_reason_code code) } static struct rejection_reason * -arity_rejection (tree first_arg, int expected, int actual) +arity_rejection (tree first_arg, int expected, int actual, bool least_p = false) { struct rejection_reason *r = alloc_rejection (rr_arity); int adjust = first_arg != NULL_TREE; r->u.arity.expected = expected - adjust; r->u.arity.actual = actual - adjust; + r->u.arity.least_p = least_p; return r; } @@ -3452,6 +3453,44 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, } gcc_assert (ia == nargs_without_in_chrg); + if (!obj && explicit_targs) + { + /* Check that there's no obvious arity mismatch before proceeding with + deduction. This avoids substituting explicit template arguments + into the template (which could result in an error outside the + immediate context) when the resulting candidate would be unviable + anyway. */ + int min_arity = 0, max_arity = 0; + tree parms = TYPE_ARG_TYPES (TREE_TYPE (tmpl)); + parms = skip_artificial_parms_for (tmpl, parms); + for (; parms != void_list_node; parms = TREE_CHAIN (parms)) + { + if (!parms || PACK_EXPANSION_P (TREE_VALUE (parms))) + { + max_arity = -1; + break; + } + if (TREE_PURPOSE (parms)) + /* A parameter with a default argument. */ + ++max_arity; + else + ++min_arity, ++max_arity; + } + if (ia < (unsigned)min_arity) + { + /* Too few arguments. */ + reason = arity_rejection (NULL_TREE, min_arity, ia, + /*least_p=*/(max_arity == -1)); + goto fail; + } + else if (max_arity != -1 && ia > (unsigned)max_arity) + { + /* Too many arguments. */ + reason = arity_rejection (NULL_TREE, max_arity, ia); + goto fail; + } + } + errs = errorcount+sorrycount; if (!obj) convs = alloc_conversions (nargs); @@ -3725,12 +3764,19 @@ print_conversion_rejection (location_t loc, struct conversion_info *info, HAVE. */ static void -print_arity_information (location_t loc, unsigned int have, unsigned int want) -{ - inform_n (loc, want, - " candidate expects %d argument, %d provided", - " candidate expects %d arguments, %d provided", - want, have); +print_arity_information (location_t loc, unsigned int have, unsigned int want, + bool least_p) +{ + if (least_p) + inform_n (loc, want, + " candidate expects at least %d argument, %d provided", + " candidate expects at least %d arguments, %d provided", + want, have); + else + inform_n (loc, want, + " candidate expects %d argument, %d provided", + " candidate expects %d arguments, %d provided", + want, have); } /* Print information about one overload candidate CANDIDATE. MSGSTR @@ -3794,7 +3840,8 @@ print_z_candidate (location_t loc, const char *msgstr, { case rr_arity: print_arity_information (cloc, r->u.arity.actual, - r->u.arity.expected); + r->u.arity.expected, + r->u.arity.least_p); break; case rr_arg_conversion: print_conversion_rejection (cloc, &r->u.conversion, fn); diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype29.C b/gcc/testsuite/g++.dg/cpp0x/decltype29.C index 51da8ddd0de..ea97b033569 100644 --- a/gcc/testsuite/g++.dg/cpp0x/decltype29.C +++ b/gcc/testsuite/g++.dg/cpp0x/decltype29.C @@ -10,10 +10,10 @@ ft() {} template decltype (ft (F())) // { dg-error "depth" } -ft() {} +ft(F) {} int main() { - ft(); // { dg-message "from here" } + ft(0); // { dg-message "from here" } } // { dg-prune-output "compilation terminated" } diff --git a/gcc/testsuite/g++.dg/template/error56.C b/gcc/testsuite/g++.dg/template/error56.C index e85471a50b0..71206a1ae5c 100644 --- a/gcc/testsuite/g++.dg/template/error56.C +++ b/gcc/testsuite/g++.dg/template/error56.C @@ -3,12 +3,12 @@ struct A { template void f(T); - void f(); + void f(int); }; int main() { - A().f<1>(); // { dg-error "f<1>" } + A().f<1>(0); // { dg-error "f<1>" } // { dg-error "type/value mismatch at argument 1" "" { target *-*-* } .-1 } // { dg-message "expected a type, got .1." "" { target *-*-* } .-2 } } diff --git a/gcc/testsuite/g++.dg/template/explicit-args6.C b/gcc/testsuite/g++.dg/template/explicit-args6.C new file mode 100644 index 00000000000..fb5e89e4cf6 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/explicit-args6.C @@ -0,0 +1,33 @@ +// PR c++/12672 +// Verify we don't substitute explicit template arguments into +// candidate function templates when the arity of the function +// template disagrees with the arity of the call. + +template +struct A { typedef typename T::type type; }; + +template void f(T); // arity 1 +template void f(T, T, T); // arity 3 + +template typename A::type f(T, T); // arity 2 +template typename A::type f(U, U); // arity 2 + +struct B { + template void f(T); // arity 1 + template void f(T, T, T); // arity 3 + + template typename A::type f(T, T); // arity 2 + template typename A::type f(U, U); // arity 2 +}; + +int main() { + // If overload resolution attempts deduction for any of the arity-2 function + // templates, the substitution of explicit arguments into the template would + // cause a hard error. + f(1); + f(1, 1, 1); + + B b; + b.f(1); + b.f(1, 1, 1); +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/unify6.C b/gcc/testsuite/g++.old-deja/g++.pt/unify6.C index d122ec2dcb9..ee14ceadd91 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/unify6.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/unify6.C @@ -23,8 +23,8 @@ template void foo(T const *){} // { dg-error "pointer to reference" } void f() { - foo(); // { dg-error "" } attempt to build int & const * - foo(); // { dg-error "" } attempt to build void (const *)() + foo(0); // { dg-error "" } attempt to build int & const * + foo(0); // OK by [dcl.fct]/7, the const is silently dropped } typedef void (*Fptr)();