Message ID | 20211110165307.4079746-1-ppalka@redhat.com |
---|---|
State | New |
Headers |
Return-Path: <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> 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 7FB5E385840C for <patchwork@sourceware.org>; Wed, 10 Nov 2021 16:53:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7FB5E385840C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1636563224; bh=eccR8xMNFpiUVx+K+V5w0RfN1uwUKE/jH8dtCylmnSM=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=OkUr4+2CerUHUGIicWQayRaungqxUTuEcKkBLyf0R+xjY97rhi4IlisAPuA3+xxYp BiHBf1DYvafCJMjCfrGXUolKOlMXmIrfLOfwstap4jMYR89vE7+bRE+XA75+s7E9Jc dL+6FVq6VtrW0ik8R+e9ZnWSMR5dBHkV4RUe/UPU= 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.129.124]) by sourceware.org (Postfix) with ESMTPS id 2B11F3858400 for <gcc-patches@gcc.gnu.org>; Wed, 10 Nov 2021 16:53:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2B11F3858400 Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-317-j1VFp8hXNpOEccEgaN8jFw-1; Wed, 10 Nov 2021 11:53:12 -0500 X-MC-Unique: j1VFp8hXNpOEccEgaN8jFw-1 Received: by mail-qk1-f200.google.com with SMTP id t15-20020a05620a450f00b0046325fa7b93so2308717qkp.1 for <gcc-patches@gcc.gnu.org>; Wed, 10 Nov 2021 08:53:12 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=eccR8xMNFpiUVx+K+V5w0RfN1uwUKE/jH8dtCylmnSM=; b=kzfwe9czaMYiNSYMj6h010Q++d2ShCQfzZlQSSkChfe2RvWCl7OmbzsV9m5SgwMORP mx8eKnfH2wSvlcq6j6LKUtjJNGXOFuHaNzrgN5pedDFbOwhKd3bZV+/HHAmJOxa+BD1t 7yVDVB4meTHPgTPiR5+0C4VUXi/3se/XpH8Gm04Eex+/x7jkGaCRGFdWD4E7z5uVxWGw 6SBvW04EX8DLMxg7/I0OIkazl3MoNB8j0oXH1d1OjgqYQiePJf67pZtOYSWHslOLrSR4 xYFksDm5J7/2CSgbQbJhF6iJa2sjAveculwsiG2MXx+DS0tKaMW6y93cVZt5cgdduAWd PVKg== X-Gm-Message-State: AOAM533BLZxr8wCDI7dJsJvi4MtbM4oj0Vv2fNSEjrgWViLpEAy8ikCv RiFgXTo3CvvpwXsY5tQmGbsYoSbnbaUh87rhKB00mD5ndP6vLr5NhspGEbOMzmC8/9w43KE1Nh1 wa9BYgK89D8NlCmoMf5RR8ePIlIT9ArBdUhTXWswWiDg7ljgoZUFVBmXYDUkhBWT5N5g= X-Received: by 2002:a0c:80e4:: with SMTP id 91mr208183qvb.57.1636563191916; Wed, 10 Nov 2021 08:53:11 -0800 (PST) X-Google-Smtp-Source: ABdhPJy+9Lgecm2YcpnigsjZDElkrmPSFGCm+y/PvmiqgNUr/tqjT5/snY4L538lVtQv4kIIxOBpAQ== X-Received: by 2002:a0c:80e4:: with SMTP id 91mr208151qvb.57.1636563191638; Wed, 10 Nov 2021 08:53:11 -0800 (PST) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id bk7sm182467qkb.72.2021.11.10.08.53.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Nov 2021 08:53:11 -0800 (PST) To: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: template-id ADL and partial instantiation [PR99911] Date: Wed, 10 Nov 2021 11:53:07 -0500 Message-Id: <20211110165307.4079746-1-ppalka@redhat.com> X-Mailer: git-send-email 2.34.0.rc1.14.g88d915a634 In-Reply-To: <20211103160419.1472321-1-ppalka@redhat.com> References: <20211103160419.1472321-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII" 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_H4, RCVD_IN_MSPIKE_WL, 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 <gcc-patches.gcc.gnu.org> List-Unsubscribe: <https://gcc.gnu.org/mailman/options/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe> List-Archive: <https://gcc.gnu.org/pipermail/gcc-patches/> List-Post: <mailto:gcc-patches@gcc.gnu.org> List-Help: <mailto:gcc-patches-request@gcc.gnu.org?subject=help> List-Subscribe: <https://gcc.gnu.org/mailman/listinfo/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe> From: Patrick Palka via Gcc-patches <gcc-patches@gcc.gnu.org> Reply-To: Patrick Palka <ppalka@redhat.com> Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> |
Series |
c++: template-id ADL and partial instantiation [PR99911]
|
|
Commit Message
Patrick Palka
Nov. 10, 2021, 4:53 p.m. UTC
Here when partially instantiating the call get<U>(T{}) with T=N::A (for which earlier unqualified name lookup for 'get' found nothing) the arguments after substitution are no longer dependent but the callee still is, so perform_koenig_lookup postpones ADL. But then we go on to diagnose the unresolved template name anyway, as if ADL was already performed and failed. This patch fixes this by avoiding the error path in question when the template arguments of an unresolved template-id are dependent, which mirrors the dependence check in perform_koenig_lookup. In passing, this patch also disables the -fpermissive fallback that performs a second unqualified lookup in the template-id ADL case; this fallback seems to be intended for legacy code and shouldn't be used for C++20 template-id ADL. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk and perhaps 11? PR c++/99911 gcc/cp/ChangeLog: * pt.c (tsubst_copy_and_build) <case CALL_EXPR>: Don't diagnose name lookup failure if the arguments to an unresolved template name are still dependent. Disable the -fpermissive fallback for template-id ADL. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/fn-template24.C: New test. --- gcc/cp/pt.c | 6 ++++-- gcc/testsuite/g++.dg/cpp2a/fn-template24.C | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/fn-template24.C
Comments
On 11/10/21 11:53, Patrick Palka wrote: > Here when partially instantiating the call get<U>(T{}) with T=N::A > (for which earlier unqualified name lookup for 'get' found nothing) > the arguments after substitution are no longer dependent but the callee > still is, so perform_koenig_lookup postpones ADL. But then we go on to > diagnose the unresolved template name anyway, as if ADL was already > performed and failed. > > This patch fixes this by avoiding the error path in question when the > template arguments of an unresolved template-id are dependent, which > mirrors the dependence check in perform_koenig_lookup. This change is OK. > In passing, this > patch also disables the -fpermissive fallback that performs a second > unqualified lookup in the template-id ADL case; this fallback seems to be > intended for legacy code and shouldn't be used for C++20 template-id ADL. Why wouldn't we want the more helpful diagnostic? > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk and perhaps 11? > > PR c++/99911 > > gcc/cp/ChangeLog: > > * pt.c (tsubst_copy_and_build) <case CALL_EXPR>: Don't diagnose > name lookup failure if the arguments to an unresolved template > name are still dependent. Disable the -fpermissive fallback for > template-id ADL. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/fn-template24.C: New test. > --- > gcc/cp/pt.c | 6 ++++-- > gcc/testsuite/g++.dg/cpp2a/fn-template24.C | 16 ++++++++++++++++ > 2 files changed, 20 insertions(+), 2 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/fn-template24.C > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index 991a20a85d4..4beddf9caf8 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -20427,12 +20427,14 @@ tsubst_copy_and_build (tree t, > if (function != NULL_TREE > && (identifier_p (function) > || (TREE_CODE (function) == TEMPLATE_ID_EXPR > - && identifier_p (TREE_OPERAND (function, 0)))) > + && identifier_p (TREE_OPERAND (function, 0)) > + && !any_dependent_template_arguments_p (TREE_OPERAND > + (function, 1)))) > && !any_type_dependent_arguments_p (call_args)) > { > if (TREE_CODE (function) == TEMPLATE_ID_EXPR) > function = TREE_OPERAND (function, 0); > - if (koenig_p && (complain & tf_warning_or_error)) > + else if (koenig_p && (complain & tf_warning_or_error)) > { > /* For backwards compatibility and good diagnostics, try > the unqualified lookup again if we aren't in SFINAE > diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template24.C b/gcc/testsuite/g++.dg/cpp2a/fn-template24.C > new file mode 100644 > index 00000000000..b444ac6a273 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/fn-template24.C > @@ -0,0 +1,16 @@ > +// PR c++/99911 > +// { dg-do compile { target c++20 } } > + > +namespace N { > + struct A { }; > + template<class T> void get(A); > +}; > + > +template<class T> > +auto f() { > + return []<class U>(U) { get<U>(T{}); }; > +} > + > +int main() { > + f<N::A>()(0); > +} >
On Thu, 18 Nov 2021, Jason Merrill wrote: > On 11/10/21 11:53, Patrick Palka wrote: > > Here when partially instantiating the call get<U>(T{}) with T=N::A > > (for which earlier unqualified name lookup for 'get' found nothing) > > the arguments after substitution are no longer dependent but the callee > > still is, so perform_koenig_lookup postpones ADL. But then we go on to > > diagnose the unresolved template name anyway, as if ADL was already > > performed and failed. > > > > This patch fixes this by avoiding the error path in question when the > > template arguments of an unresolved template-id are dependent, which > > mirrors the dependence check in perform_koenig_lookup. > > This change is OK. > > > In passing, this > > patch also disables the -fpermissive fallback that performs a second > > unqualified lookup in the template-id ADL case; this fallback seems to be > > intended for legacy code and shouldn't be used for C++20 template-id ADL. > > Why wouldn't we want the more helpful diagnostic? The "no declarations were found by ADL" diagnostic is helpful, but the backwards compatibility logic doesn't correctly handle the template-id case. E.g. for template<class T> void f() { g<int>(T{}); } template<class T> void g(int); // #1 int main() { f<int>(); } we get the helpful diagnostic followed by a confusing one because we didn't incorporate the template-id's template arguments when replacing the callee with the later-declared template #1: <stdin>: In instantiation of ‘void f() [with T = int]’: <stdin>:10:9: required from here <stdin>:3:6: error: ‘g’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] <stdin>:7:6: note: ‘template<class T> void g(int)’ declared here, later in the translation unit <stdin>:3:6: error: no matching function for call to ‘g(int)’ <stdin>:7:6: note: candidate: ‘template<class T> void g(int)’ <stdin>:7:6: note: template argument deduction/substitution failed: <stdin>:3:6: note: couldn’t deduce template parameter ‘T’ We also ignores template-ness of the name being looked up, so e.g. for: template<class T> void f() { g<>(T{}); } void g(int); // #1 int main() { f<int>(); } the secondary unqualified lookup finds the later-declared non-template #1: <stdin>: In instantiation of ‘void f() [with T = int]’: <stdin>:9:9: required from here <stdin>:3:6: error: ‘g’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] <stdin>:6:6: note: ‘void g(int)’ declared here, later in the translation unit which doesn't seem right. To fix the first issue, rather than disabling the diagnostic perhaps we should just disable the backwards compatibility logic in the template-id case, as in the below? -- >8 -- diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 82bf7dc26f6..e2d04a52894 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20428,7 +20428,8 @@ tsubst_copy_and_build (tree t, && identifier_p (TREE_OPERAND (function, 0)))) && !any_type_dependent_arguments_p (call_args)) { - if (TREE_CODE (function) == TEMPLATE_ID_EXPR) + bool template_id_p = (TREE_CODE (function) == TEMPLATE_ID_EXPR); + if (template_id_p) function = TREE_OPERAND (function, 0); if (koenig_p && (complain & tf_warning_or_error)) { @@ -20443,20 +20444,21 @@ tsubst_copy_and_build (tree t, if (unq != function) { - /* In a lambda fn, we have to be careful to not - introduce new this captures. Legacy code can't - be using lambdas anyway, so it's ok to be - stricter. */ - bool in_lambda = (current_class_type - && LAMBDA_TYPE_P (current_class_type)); char const *const msg = G_("%qD was not declared in this scope, " "and no declarations were found by " "argument-dependent lookup at the point " "of instantiation"); + bool in_lambda = (current_class_type + && LAMBDA_TYPE_P (current_class_type)); + /* In a lambda fn, we have to be careful to not + introduce new this captures. Legacy code can't + be using lambdas anyway, so it's ok to be + stricter. Be strict with C++20 template-id ADL too. */ + bool strict = in_lambda || template_id_p; bool diag = true; - if (in_lambda) + if (strict) error_at (cp_expr_loc_or_input_loc (t), msg, function); else @@ -20492,7 +20494,7 @@ tsubst_copy_and_build (tree t, inform (DECL_SOURCE_LOCATION (fn), "%qD declared here, later in the " "translation unit", fn); - if (in_lambda) + if (strict) RETURN (error_mark_node); }
On Thu, 18 Nov 2021, Patrick Palka wrote: > On Thu, 18 Nov 2021, Jason Merrill wrote: > > > On 11/10/21 11:53, Patrick Palka wrote: > > > Here when partially instantiating the call get<U>(T{}) with T=N::A > > > (for which earlier unqualified name lookup for 'get' found nothing) > > > the arguments after substitution are no longer dependent but the callee > > > still is, so perform_koenig_lookup postpones ADL. But then we go on to > > > diagnose the unresolved template name anyway, as if ADL was already > > > performed and failed. > > > > > > This patch fixes this by avoiding the error path in question when the > > > template arguments of an unresolved template-id are dependent, which > > > mirrors the dependence check in perform_koenig_lookup. > > > > This change is OK. > > > > > In passing, this > > > patch also disables the -fpermissive fallback that performs a second > > > unqualified lookup in the template-id ADL case; this fallback seems to be > > > intended for legacy code and shouldn't be used for C++20 template-id ADL. > > > > Why wouldn't we want the more helpful diagnostic? > > The "no declarations were found by ADL" diagnostic is helpful, but the > backwards compatibility logic doesn't correctly handle the template-id > case. E.g. for > > template<class T> > void f() { > g<int>(T{}); > } > > template<class T> > void g(int); // #1 > > int main() { > f<int>(); > } > > we get the helpful diagnostic followed by a confusing one because we > didn't incorporate the template-id's template arguments when replacing > the callee with the later-declared template #1: > > <stdin>: In instantiation of ‘void f() [with T = int]’: > <stdin>:10:9: required from here > <stdin>:3:6: error: ‘g’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] > <stdin>:7:6: note: ‘template<class T> void g(int)’ declared here, later in the translation unit > <stdin>:3:6: error: no matching function for call to ‘g(int)’ > <stdin>:7:6: note: candidate: ‘template<class T> void g(int)’ > <stdin>:7:6: note: template argument deduction/substitution failed: > <stdin>:3:6: note: couldn’t deduce template parameter ‘T’ > > > We also ignores template-ness of the name being looked up, so e.g. for: > > template<class T> > void f() { > g<>(T{}); > } > > void g(int); // #1 > > int main() { > f<int>(); > } > > the secondary unqualified lookup finds the later-declared non-template #1: > > <stdin>: In instantiation of ‘void f() [with T = int]’: > <stdin>:9:9: required from here > <stdin>:3:6: error: ‘g’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] > <stdin>:6:6: note: ‘void g(int)’ declared here, later in the translation unit > > which doesn't seem right. > > To fix the first issue, rather than disabling the diagnostic perhaps we > should just disable the backwards compatibility logic in the template-id > case, as in the below? Now in patch form: -- >8 -- Subject: [PATCH] c++: error recovery during C++20 template-id ADL failure When diagnosing ADL failure we perform a second unqualified lookup for backwards compatibility with legacy code, and for better diagnostics. For C++20 template-id ADL however, the backwards compatibility logic causes confusing subsequent diagnostics, such as in the testcase below where we report deduction failure following the useful "no declarations were found by ADL" diagnostic because we've discarded the arguments of the template-id when replacing it with the later-declared template. So for C++20 template-id ADL, this patch just disables the backwards compatibility code while keeping the useful diagnostic. gcc/cp/ChangeLog: * pt.c (tsubst_copy_and_build) <case CALL_EXPR>: Disable the -fpermissive fallback for template-id ADL, but keep the diagnostic. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/fn-template25.C: New test. --- gcc/cp/pt.c | 23 +++++++++++++--------- gcc/testsuite/g++.dg/cpp2a/fn-template25.C | 14 +++++++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/fn-template25.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ad51c07347b..3f1550a17ad 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20439,8 +20439,12 @@ tsubst_copy_and_build (tree t, (function, 1)))) && !any_type_dependent_arguments_p (call_args)) { + bool template_id_p = false; if (TREE_CODE (function) == TEMPLATE_ID_EXPR) - function = TREE_OPERAND (function, 0); + { + function = TREE_OPERAND (function, 0); + template_id_p = true; + } if (koenig_p && (complain & tf_warning_or_error)) { /* For backwards compatibility and good diagnostics, try @@ -20454,20 +20458,21 @@ tsubst_copy_and_build (tree t, if (unq != function) { - /* In a lambda fn, we have to be careful to not - introduce new this captures. Legacy code can't - be using lambdas anyway, so it's ok to be - stricter. */ - bool in_lambda = (current_class_type - && LAMBDA_TYPE_P (current_class_type)); char const *const msg = G_("%qD was not declared in this scope, " "and no declarations were found by " "argument-dependent lookup at the point " "of instantiation"); + bool in_lambda = (current_class_type + && LAMBDA_TYPE_P (current_class_type)); + /* In a lambda fn, we have to be careful to not + introduce new this captures. Legacy code can't + be using lambdas anyway, so it's ok to be + stricter. Be strict with C++20 template-id ADL too. */ + bool strict = in_lambda || template_id_p; bool diag = true; - if (in_lambda) + if (strict) error_at (cp_expr_loc_or_input_loc (t), msg, function); else @@ -20503,7 +20508,7 @@ tsubst_copy_and_build (tree t, inform (DECL_SOURCE_LOCATION (fn), "%qD declared here, later in the " "translation unit", fn); - if (in_lambda) + if (strict) RETURN (error_mark_node); } diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template25.C b/gcc/testsuite/g++.dg/cpp2a/fn-template25.C new file mode 100644 index 00000000000..a8888af2023 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/fn-template25.C @@ -0,0 +1,14 @@ +// { dg-do compile { target c++20 } } + +template<class T> +void f() { + g<int>(T{}); // { dg-error "argument-dependent lookup" } + // { dg-bogus "no match" "" { target *-*-* } .-1 } +} + +template<class T> +void g(int); // { dg-message "declared here, later" } + +int main() { + f<int>(); +}
On 11/18/21 10:31, Patrick Palka wrote: > On Thu, 18 Nov 2021, Patrick Palka wrote: > >> On Thu, 18 Nov 2021, Jason Merrill wrote: >> >>> On 11/10/21 11:53, Patrick Palka wrote: >>>> Here when partially instantiating the call get<U>(T{}) with T=N::A >>>> (for which earlier unqualified name lookup for 'get' found nothing) >>>> the arguments after substitution are no longer dependent but the callee >>>> still is, so perform_koenig_lookup postpones ADL. But then we go on to >>>> diagnose the unresolved template name anyway, as if ADL was already >>>> performed and failed. >>>> >>>> This patch fixes this by avoiding the error path in question when the >>>> template arguments of an unresolved template-id are dependent, which >>>> mirrors the dependence check in perform_koenig_lookup. >>> >>> This change is OK. >>> >>>> In passing, this >>>> patch also disables the -fpermissive fallback that performs a second >>>> unqualified lookup in the template-id ADL case; this fallback seems to be >>>> intended for legacy code and shouldn't be used for C++20 template-id ADL. >>> >>> Why wouldn't we want the more helpful diagnostic? >> >> The "no declarations were found by ADL" diagnostic is helpful, but the >> backwards compatibility logic doesn't correctly handle the template-id >> case. E.g. for >> >> template<class T> >> void f() { >> g<int>(T{}); >> } >> >> template<class T> >> void g(int); // #1 >> >> int main() { >> f<int>(); >> } >> >> we get the helpful diagnostic followed by a confusing one because we >> didn't incorporate the template-id's template arguments when replacing >> the callee with the later-declared template #1: >> >> <stdin>: In instantiation of ‘void f() [with T = int]’: >> <stdin>:10:9: required from here >> <stdin>:3:6: error: ‘g’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] >> <stdin>:7:6: note: ‘template<class T> void g(int)’ declared here, later in the translation unit >> <stdin>:3:6: error: no matching function for call to ‘g(int)’ >> <stdin>:7:6: note: candidate: ‘template<class T> void g(int)’ >> <stdin>:7:6: note: template argument deduction/substitution failed: >> <stdin>:3:6: note: couldn’t deduce template parameter ‘T’ >> >> >> We also ignores template-ness of the name being looked up, so e.g. for: >> >> template<class T> >> void f() { >> g<>(T{}); >> } >> >> void g(int); // #1 >> >> int main() { >> f<int>(); >> } >> >> the secondary unqualified lookup finds the later-declared non-template #1: >> >> <stdin>: In instantiation of ‘void f() [with T = int]’: >> <stdin>:9:9: required from here >> <stdin>:3:6: error: ‘g’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] >> <stdin>:6:6: note: ‘void g(int)’ declared here, later in the translation unit >> >> which doesn't seem right. >> >> To fix the first issue, rather than disabling the diagnostic perhaps we >> should just disable the backwards compatibility logic in the template-id >> case, as in the below? > > Now in patch form: > > -- >8 -- > > Subject: [PATCH] c++: error recovery during C++20 template-id ADL failure > > When diagnosing ADL failure we perform a second unqualified lookup for > backwards compatibility with legacy code, and for better diagnostics. > > For C++20 template-id ADL however, the backwards compatibility logic > causes confusing subsequent diagnostics, such as in the testcase below > where we report deduction failure following the useful "no declarations > were found by ADL" diagnostic because we've discarded the arguments of > the template-id when replacing it with the later-declared template. > > So for C++20 template-id ADL, this patch just disables the backwards > compatibility code while keeping the useful diagnostic. > > gcc/cp/ChangeLog: > > * pt.c (tsubst_copy_and_build) <case CALL_EXPR>: Disable the > -fpermissive fallback for template-id ADL, but keep the > diagnostic. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/fn-template25.C: New test. > --- > gcc/cp/pt.c | 23 +++++++++++++--------- > gcc/testsuite/g++.dg/cpp2a/fn-template25.C | 14 +++++++++++++ > 2 files changed, 28 insertions(+), 9 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/fn-template25.C > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index ad51c07347b..3f1550a17ad 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -20439,8 +20439,12 @@ tsubst_copy_and_build (tree t, > (function, 1)))) > && !any_type_dependent_arguments_p (call_args)) > { > + bool template_id_p = false; > if (TREE_CODE (function) == TEMPLATE_ID_EXPR) > - function = TREE_OPERAND (function, 0); > + { > + function = TREE_OPERAND (function, 0); > + template_id_p = true; > + } I think bool template_id_p = TREE_CODE (function) == TEMPLATE_ID_EXPR; would simplify this. OK either way. > if (koenig_p && (complain & tf_warning_or_error)) > { > /* For backwards compatibility and good diagnostics, try > @@ -20454,20 +20458,21 @@ tsubst_copy_and_build (tree t, > > if (unq != function) > { > - /* In a lambda fn, we have to be careful to not > - introduce new this captures. Legacy code can't > - be using lambdas anyway, so it's ok to be > - stricter. */ > - bool in_lambda = (current_class_type > - && LAMBDA_TYPE_P (current_class_type)); > char const *const msg > = G_("%qD was not declared in this scope, " > "and no declarations were found by " > "argument-dependent lookup at the point " > "of instantiation"); > > + bool in_lambda = (current_class_type > + && LAMBDA_TYPE_P (current_class_type)); > + /* In a lambda fn, we have to be careful to not > + introduce new this captures. Legacy code can't > + be using lambdas anyway, so it's ok to be > + stricter. Be strict with C++20 template-id ADL too. */ > + bool strict = in_lambda || template_id_p; > bool diag = true; > - if (in_lambda) > + if (strict) > error_at (cp_expr_loc_or_input_loc (t), > msg, function); > else > @@ -20503,7 +20508,7 @@ tsubst_copy_and_build (tree t, > inform (DECL_SOURCE_LOCATION (fn), > "%qD declared here, later in the " > "translation unit", fn); > - if (in_lambda) > + if (strict) > RETURN (error_mark_node); > } > > diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template25.C b/gcc/testsuite/g++.dg/cpp2a/fn-template25.C > new file mode 100644 > index 00000000000..a8888af2023 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/fn-template25.C > @@ -0,0 +1,14 @@ > +// { dg-do compile { target c++20 } } > + > +template<class T> > +void f() { > + g<int>(T{}); // { dg-error "argument-dependent lookup" } > + // { dg-bogus "no match" "" { target *-*-* } .-1 } > +} > + > +template<class T> > +void g(int); // { dg-message "declared here, later" } > + > +int main() { > + f<int>(); > +} >
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 991a20a85d4..4beddf9caf8 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20427,12 +20427,14 @@ tsubst_copy_and_build (tree t, if (function != NULL_TREE && (identifier_p (function) || (TREE_CODE (function) == TEMPLATE_ID_EXPR - && identifier_p (TREE_OPERAND (function, 0)))) + && identifier_p (TREE_OPERAND (function, 0)) + && !any_dependent_template_arguments_p (TREE_OPERAND + (function, 1)))) && !any_type_dependent_arguments_p (call_args)) { if (TREE_CODE (function) == TEMPLATE_ID_EXPR) function = TREE_OPERAND (function, 0); - if (koenig_p && (complain & tf_warning_or_error)) + else if (koenig_p && (complain & tf_warning_or_error)) { /* For backwards compatibility and good diagnostics, try the unqualified lookup again if we aren't in SFINAE diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template24.C b/gcc/testsuite/g++.dg/cpp2a/fn-template24.C new file mode 100644 index 00000000000..b444ac6a273 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/fn-template24.C @@ -0,0 +1,16 @@ +// PR c++/99911 +// { dg-do compile { target c++20 } } + +namespace N { + struct A { }; + template<class T> void get(A); +}; + +template<class T> +auto f() { + return []<class U>(U) { get<U>(T{}); }; +} + +int main() { + f<N::A>()(0); +}