From patchwork Thu Mar 3 20:06:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 51536 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 A04D83858038 for ; Thu, 3 Mar 2022 20:07:32 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A04D83858038 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1646338052; bh=zZMH86Q3S2MF/iwDvRe2Prlf9/V7rRLgkajSI+oh46M=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=fouP+kIPsoLYQDq6wHLmoqNTonTC8rKMHRNbULb9ha6NmlUfyttUdBmlMAlGSoFHY OZRobd8rwzO7YMGqOCjuaLeY/xflFmRAk8BdRLc4Mfmp/eIiJCtARq9lGkdrc79ghP 6M6sFFSpbC+TXZwiXuhdqXjupqA/tJDm5m9NiXKc= 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 ESMTPS id F13A93858407 for ; Thu, 3 Mar 2022 20:07:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org F13A93858407 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-468-wwkfexBpNc293blOEPWfJg-1; Thu, 03 Mar 2022 15:06:58 -0500 X-MC-Unique: wwkfexBpNc293blOEPWfJg-1 Received: by mail-qt1-f200.google.com with SMTP id f13-20020ac8014d000000b002ddae786fb0so4387179qtg.19 for ; Thu, 03 Mar 2022 12:06:58 -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:mime-version :content-transfer-encoding; bh=zZMH86Q3S2MF/iwDvRe2Prlf9/V7rRLgkajSI+oh46M=; b=OcP2kPTW2gqb+iiD+OWU4owuAYF0+pwKPG3ngb5xP4+OCAfoWwxwhHNYwfPACn6z4g xJ6pfuCyVT6y6/ZlV42Rv2l/Ha8DrZZbhETM8kGlDjTC2bB1oTnxKEiphen1arfV+pec POPPeXsVKTD3UN6lT0SNXrFvzmCvmwZvszn7fUUmVxYQgg8UBUmxsEhxdpGhVnfYqZBX BFL8RPURADg9DPU2agpyr4gTfX9rXLyoJGUDSPiD6EwyvwKWbZ03NFcnf3QuMK5pYH53 Eckh8kp5XEk2b+XCb7hxValeKJ1rIbcyWuIUFmGgo/luifvmLNn1Y+/9MMTn0qiw+06I nsew== X-Gm-Message-State: AOAM5339vXGl++dPIxh7ruRKj9sklxvdZciTXA24KkVKtHwUcd0jNERY LkXjmLyg6Nwjm7M2cBJb4rwSVjc2y9asxumiL0ye+wOOTKdryIFXxBPGy/d01tX3bIMDImbeUJC 89eHZszk5wbGe6JF5xizts1xPQziVEJHCtMrGz5f5TdTEa2G/KJIOxZDFckts9Ine0zc= X-Received: by 2002:a37:6792:0:b0:62c:ecdd:8071 with SMTP id b140-20020a376792000000b0062cecdd8071mr544625qkc.417.1646338017745; Thu, 03 Mar 2022 12:06:57 -0800 (PST) X-Google-Smtp-Source: ABdhPJxA8zadQvMQURZwBJ6ecGt4F99VxPkKPYA+dP0nfAPZJEZ5oFEWsYAACR1oCLIk+8xgKe/+QA== X-Received: by 2002:a37:6792:0:b0:62c:ecdd:8071 with SMTP id b140-20020a376792000000b0062cecdd8071mr544592qkc.417.1646338017224; Thu, 03 Mar 2022 12:06:57 -0800 (PST) Received: from localhost.localdomain (ool-18e40894.dyn.optonline.net. [24.228.8.148]) by smtp.gmail.com with ESMTPSA id c11-20020a05622a024b00b002ddb43850fdsm2010439qtx.15.2022.03.03.12.06.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Mar 2022 12:06:56 -0800 (PST) To: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: merge default targs for function templates [PR65396] Date: Thu, 3 Mar 2022 15:06:53 -0500 Message-Id: <20220303200653.3352485-1-ppalka@redhat.com> X-Mailer: git-send-email 2.35.1.354.g715d08a9e5 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-14.5 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_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" We currently merge default template arguments for class templates, but not for function templates. This patch fixes this by splitting out the argument merging logic in redeclare_class_template into a separate function and using it in duplicate_decls as well. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? PR c++/65396 gcc/cp/ChangeLog: * cp-tree.h (merge_default_template_args): Declare. * decl.cc (merge_default_template_args): Define, split out from redeclare_class_template. (duplicate_decls): Use it when merging member function template and free function declarations. * pt.cc (redeclare_class_template): Split out default argument merging logic into merge_default_template_args. Improve location of a note when there's a template parameter kind mismatch. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/vt-34314.C: Adjust expected location of "redeclared here" note. * g++.dg/template/pr92440.C: Likewise. * g++.old-deja/g++.pt/redecl1.C: Adjust expected location of "redefinition of default argument" error. * g++.dg/template/defarg23.C: New test. * g++.dg/template/defarg23a.C: New test. --- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.cc | 60 ++++++++++++++++++++- gcc/cp/pt.cc | 31 ++--------- gcc/testsuite/g++.dg/cpp0x/vt-34314.C | 12 ++--- gcc/testsuite/g++.dg/template/defarg23.C | 21 ++++++++ gcc/testsuite/g++.dg/template/defarg23a.C | 24 +++++++++ gcc/testsuite/g++.dg/template/pr92440.C | 4 +- gcc/testsuite/g++.old-deja/g++.pt/redecl1.C | 12 ++--- 8 files changed, 123 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/defarg23.C create mode 100644 gcc/testsuite/g++.dg/template/defarg23a.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8a44218611f..ea53e2d0ef2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6783,6 +6783,7 @@ extern void note_iteration_stmt_body_end (bool); extern void determine_local_discriminator (tree); extern int decls_match (tree, tree, bool = true); extern bool maybe_version_functions (tree, tree, bool); +extern bool merge_default_template_args (tree, tree, bool); extern tree duplicate_decls (tree, tree, bool hiding = false, bool was_hidden = false); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 23c06655bde..a0bce56c121 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -1470,6 +1470,43 @@ duplicate_function_template_decls (tree newdecl, tree olddecl) return false; } +/* OLD_PARMS is the innermost set of template parameters for some template + declaration, and NEW_PARMS is the corresponding set of template parameters + for a redeclaration of that template. Merge the default arguments within + these two sets of parameters. CLASS_P is true iff the template in + question is a class template. */ + +bool +merge_default_template_args (tree new_parms, tree old_parms, bool class_p) +{ + gcc_checking_assert (TREE_VEC_LENGTH (new_parms) + == TREE_VEC_LENGTH (old_parms)); + for (int i = 0; i < TREE_VEC_LENGTH (new_parms); i++) + { + tree new_parm = TREE_VALUE (TREE_VEC_ELT (new_parms, i)); + tree old_parm = TREE_VALUE (TREE_VEC_ELT (old_parms, i)); + tree& new_default = TREE_PURPOSE (TREE_VEC_ELT (new_parms, i)); + tree& old_default = TREE_PURPOSE (TREE_VEC_ELT (old_parms, i)); + if (new_default != NULL_TREE && old_default != NULL_TREE) + { + auto_diagnostic_group d; + error ("redefinition of default argument for %q+#D", new_parm); + inform (DECL_SOURCE_LOCATION (old_parm), + "original definition appeared here"); + return false; + } + else if (new_default != NULL_TREE) + /* Update the previous template parameters (which are the ones + that will really count) with the new default value. */ + old_default = new_default; + else if (class_p && old_default != NULL_TREE) + /* Update the new parameters, too; they'll be used as the + parameters for any members. */ + new_default = old_default; + } + return true; +} + /* If NEWDECL is a redeclaration of OLDDECL, merge the declarations. If the redeclaration is invalid, a diagnostic is issued, and the error_mark_node is returned. Otherwise, OLDDECL is returned. @@ -1990,7 +2027,23 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) template shall be specified on the initial declaration of the member function within the class template. */ || CLASSTYPE_TEMPLATE_INFO (CP_DECL_CONTEXT (olddecl)))) - check_redeclaration_no_default_args (newdecl); + { + check_redeclaration_no_default_args (newdecl); + + if (DECL_TEMPLATE_INFO (olddecl) + && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (olddecl))) + { + /* NEWDECL doesn't have its own TEMPLATE_INFO, so we need to + use current_template_parms. */ + gcc_checking_assert (!DECL_TEMPLATE_INFO (newdecl)); + tree new_parms + = INNERMOST_TEMPLATE_PARMS (current_template_parms); + tree old_parms + = DECL_INNERMOST_TEMPLATE_PARMS (DECL_TI_TEMPLATE (olddecl)); + merge_default_template_args (new_parms, old_parms, + /*class_p=*/false); + } + } else { tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl); @@ -2235,6 +2288,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) translation unit." */ check_no_redeclaration_friend_default_args (old_result, new_result); + + tree new_parms = DECL_INNERMOST_TEMPLATE_PARMS (newdecl); + tree old_parms = DECL_INNERMOST_TEMPLATE_PARMS (olddecl); + merge_default_template_args (new_parms, old_parms, + /*class_p=*/false); } if (!DECL_UNIQUE_FRIEND_P (old_result)) DECL_UNIQUE_FRIEND_P (new_result) = false; diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 18a21572ce3..d94d4538faa 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -6274,8 +6274,6 @@ redeclare_class_template (tree type, tree parms, tree cons) { tree tmpl_parm; tree parm; - tree tmpl_default; - tree parm_default; if (TREE_VEC_ELT (tmpl_parms, i) == error_mark_node || TREE_VEC_ELT (parms, i) == error_mark_node) @@ -6286,8 +6284,6 @@ redeclare_class_template (tree type, tree parms, tree cons) return false; parm = TREE_VALUE (TREE_VEC_ELT (parms, i)); - tmpl_default = TREE_PURPOSE (TREE_VEC_ELT (tmpl_parms, i)); - parm_default = TREE_PURPOSE (TREE_VEC_ELT (parms, i)); /* TMPL_PARM and PARM can be either TYPE_DECL, PARM_DECL, or TEMPLATE_DECL. */ @@ -6303,7 +6299,7 @@ redeclare_class_template (tree type, tree parms, tree cons) { auto_diagnostic_group d; error ("template parameter %q+#D", tmpl_parm); - inform (input_location, "redeclared here as %q#D", parm); + inform (DECL_SOURCE_LOCATION (parm), "redeclared here as %q#D", parm); return false; } @@ -6321,28 +6317,6 @@ redeclare_class_template (tree type, tree parms, tree cons) return false; } - if (tmpl_default != NULL_TREE && parm_default != NULL_TREE) - { - /* We have in [temp.param]: - - A template-parameter may not be given default arguments - by two different declarations in the same scope. */ - auto_diagnostic_group d; - error_at (input_location, "redefinition of default argument for %q#D", parm); - inform (DECL_SOURCE_LOCATION (tmpl_parm), - "original definition appeared here"); - return false; - } - - if (parm_default != NULL_TREE) - /* Update the previous template parameters (which are the ones - that will really count) with the new default value. */ - TREE_PURPOSE (TREE_VEC_ELT (tmpl_parms, i)) = parm_default; - else if (tmpl_default != NULL_TREE) - /* Update the new parameters, too; they'll be used as the - parameters for any members. */ - TREE_PURPOSE (TREE_VEC_ELT (parms, i)) = tmpl_default; - /* Give each template template parm in this redeclaration a DECL_CONTEXT of the template for which they are a parameter. */ if (TREE_CODE (parm) == TEMPLATE_DECL) @@ -6352,6 +6326,9 @@ redeclare_class_template (tree type, tree parms, tree cons) } } + if (!merge_default_template_args (parms, tmpl_parms, /*class_p=*/true)) + return false; + tree ci = get_constraints (tmpl); tree req1 = ci ? CI_TEMPLATE_REQS (ci) : NULL_TREE; tree req2 = cons ? CI_TEMPLATE_REQS (cons) : NULL_TREE; diff --git a/gcc/testsuite/g++.dg/cpp0x/vt-34314.C b/gcc/testsuite/g++.dg/cpp0x/vt-34314.C index b37cac53223..704a975cc95 100644 --- a/gcc/testsuite/g++.dg/cpp0x/vt-34314.C +++ b/gcc/testsuite/g++.dg/cpp0x/vt-34314.C @@ -3,8 +3,8 @@ template // { dg-error "template parameter" } struct call; -template -struct call // { dg-message "note: redeclared here" } +template // { dg-message "note: redeclared here" } +struct call { template struct result; @@ -20,8 +20,8 @@ struct call // { dg-message "note: redeclared here" } template // { dg-error "template parameter" } struct call2; -template -struct call2 // { dg-message "note: redeclared here" } +template // { dg-message "note: redeclared here" } +struct call2 { template struct result; @@ -36,8 +36,8 @@ struct call2 // { dg-message "note: redeclared here" } template class... TT> // { dg-error "template parameter" } struct call3; -template class TT> -struct call3 // { dg-message "note: redeclared here" } +template class TT> // { dg-message "note: redeclared here" } +struct call3 { template struct result; diff --git a/gcc/testsuite/g++.dg/template/defarg23.C b/gcc/testsuite/g++.dg/template/defarg23.C new file mode 100644 index 00000000000..443d02656cc --- /dev/null +++ b/gcc/testsuite/g++.dg/template/defarg23.C @@ -0,0 +1,21 @@ +// PR c++/65396 +// { dg-do compile { target c++11 } } + +template void f(); +template void f(); + +template void g(); // { dg-message "original definition" } +template void g(); // { dg-error "redefinition of default" } + +template void h(); +template +void h() { + static_assert(__is_same(T, char), ""); + static_assert(__is_same(U, bool), ""); +} + +int main() { + f(); + g(); + h(); +} diff --git a/gcc/testsuite/g++.dg/template/defarg23a.C b/gcc/testsuite/g++.dg/template/defarg23a.C new file mode 100644 index 00000000000..3de0306112e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/defarg23a.C @@ -0,0 +1,24 @@ +// PR c++/65396 +// { dg-do compile { target c++11 } } +// Like defarg23.C, but for member functions. + +struct A { + template void f(); + template void g(); // { dg-message "original definition" } + template void h(); +}; + +template void A::f() { } +template void A::g() { } // { dg-error "redefinition of default" } +template +void A::h() { + static_assert(__is_same(T, char), ""); + static_assert(__is_same(U, bool), ""); +} + +int main() { + A a; + a.f(); + a.g(); + a.h(); +} diff --git a/gcc/testsuite/g++.dg/template/pr92440.C b/gcc/testsuite/g++.dg/template/pr92440.C index 20db5f10586..f1e9281ab86 100644 --- a/gcc/testsuite/g++.dg/template/pr92440.C +++ b/gcc/testsuite/g++.dg/template/pr92440.C @@ -3,8 +3,8 @@ template // { dg-error "template parameter" } struct S { - template - friend struct S; // { dg-message "note: redeclared here as" } + template // { dg-message "note: redeclared here as" } + friend struct S; }; S<0> s; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/redecl1.C b/gcc/testsuite/g++.old-deja/g++.pt/redecl1.C index 48517f5d1d3..7596513acc0 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/redecl1.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/redecl1.C @@ -9,14 +9,14 @@ struct S1 {}; // { dg-error "redeclared" } used 1 template parameter template // { dg-message "original definition" } struct S2; -template -struct S2; // { dg-error "redefinition of default" } +template // { dg-error "redefinition of default" } +struct S2; template // { dg-error "template parameter" } struct S3; -template -struct S3; // { dg-message "note: redeclared here" } +template // { dg-message "note: redeclared here" } +struct S3; -template