Message ID | 20210916131115.2330482-1-ppalka@redhat.com |
---|---|
State | Committed |
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 82C023857411 for <patchwork@sourceware.org>; Thu, 16 Sep 2021 13:11:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 82C023857411 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1631797908; bh=6k3ROqkTVhXbY2oxwXXWU5Ej9b72wFU9StFLfy5mvkA=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=rQ64iX5mVUYzzgB8L96SIHUOpybuld6a8HKgKLH4GOJ9fzHKYoypOpKACR4bZcePW wctTcPbvAtBXGGy8wrsahIF4SjfAe36asfphgbVglF55zxN/ni3v4iFBRP6dbXpDSs acD7XEtUMna7SbVC4t37LyzAs1s8chiNsq3cWs/0= 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 [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 0FD783858C39 for <gcc-patches@gcc.gnu.org>; Thu, 16 Sep 2021 13:11:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0FD783858C39 Received: from mail-qv1-f70.google.com (mail-qv1-f70.google.com [209.85.219.70]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-237-zd4UXidIOIiV4-BMFNlvcQ-1; Thu, 16 Sep 2021 09:11:18 -0400 X-MC-Unique: zd4UXidIOIiV4-BMFNlvcQ-1 Received: by mail-qv1-f70.google.com with SMTP id u8-20020a0cee88000000b00363b89e1c50so50005313qvr.16 for <gcc-patches@gcc.gnu.org>; Thu, 16 Sep 2021 06:11:18 -0700 (PDT) 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=6k3ROqkTVhXbY2oxwXXWU5Ej9b72wFU9StFLfy5mvkA=; b=bvpKqGWnVQ8e3zkWi75uBJYlkFoaZHxZOzPmtdKb8VSegVLs8FcgYOf5HfJsuyG8vd f/CaJkNO4XdLnVFjDjyXWasHcrhpNiA/0hMKa2aA/q5DhjQi+4rkWrXJRfPwozsGy8Cn rQkZb6/ezeByTNpS4m0cULnn+hP5rKD7B5jgj6Ep18OdRb0D2Eu8Arm2qj3Mm/QbkbIh 117Kkxb342BGAUtXGQkA55VLq0V/mbkOlUsdOBLhieeacU3eP6KRej8YZPSo88+TDy0F cGFHvK/DnWdWXw6ieyZOGsZq2iJGdIHvGyv5YGFBUX7fkW3IiWqxL8yQUQFO6rw/6CdS nHbg== X-Gm-Message-State: AOAM5334m/imvto6srZ86e1Tmu/YFE0jtiuSj3OcSZfsB9AktoiThkQv srMqt0NZUmIYKhgIZnsqI5Svw6AJLWMobFtGWfaSiEQBkPA4jerJwHcUiojXVtUQ8m+3DPq/wuX Ucb0hAYMutnybRbXbTdDVPPXFzYQJJSq40dey8iBkjdZBDatHC+Wq9HGD1tbj0nKkAnk= X-Received: by 2002:ac8:5617:: with SMTP id 23mr4875851qtr.20.1631797877793; Thu, 16 Sep 2021 06:11:17 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxpEouiKlzB/8HZ61RjzB/VTicVZsP3b/gmAd2LwZQHZWvHYEf2B2jDquHOOxXLQ3bnD30dpg== X-Received: by 2002:ac8:5617:: with SMTP id 23mr4875817qtr.20.1631797877419; Thu, 16 Sep 2021 06:11:17 -0700 (PDT) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id f24sm399145qtq.25.2021.09.16.06.11.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Sep 2021 06:11:17 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: constrained variable template issues [PR98486] Date: Thu, 16 Sep 2021 09:11:15 -0400 Message-Id: <20210916131115.2330482-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 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_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 <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++: constrained variable template issues [PR98486]
|
|
Commit Message
Patrick Palka
Sept. 16, 2021, 1:11 p.m. UTC
This fixes some issues with constrained variable templates: * Constraints aren't checked when explicitly specializing a variable template * Constraints aren't attached to a static data member template at parse time * Constraints aren't propagated when (partially) instantiating a static data member template Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested on cmcstl2 and range-v3, does this look OK for trunk and perhaps 11? PR c++/98486 gcc/cp/ChangeLog: * decl.c (grokdeclarator): Set constraints on a static data member template. * pt.c (determine_specialization): Check constraints on a variable template. (tsubst_decl) <case VAR_DECL>: Propagate constraints on a static data member template. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-var-templ1.C: New test. * g++.dg/cpp2a/concepts-var-templ1a.C: New test. * g++.dg/cpp2a/concepts-var-templ1b.C: New test. --- gcc/cp/decl.c | 11 +++++++++++ gcc/cp/pt.c | 8 +++++++- gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C | 9 +++++++++ gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C | 14 ++++++++++++++ gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C | 15 +++++++++++++++ 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C
Comments
On 9/16/21 09:11, Patrick Palka wrote: > This fixes some issues with constrained variable templates: > > * Constraints aren't checked when explicitly specializing a variable > template > * Constraints aren't attached to a static data member template at > parse time > * Constraints aren't propagated when (partially) instantiating a > static data member template > > Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested on > cmcstl2 and range-v3, does this look OK for trunk and perhaps 11? > > PR c++/98486 > > gcc/cp/ChangeLog: > > * decl.c (grokdeclarator): Set constraints on a static data > member template. > * pt.c (determine_specialization): Check constraints on a > variable template. These hunks are OK. > (tsubst_decl) <case VAR_DECL>: Propagate constraints on a > static data member template. Hmm, why is this necessary? I know we already do this for functions, but I don't remember why. Don't we check satisfaction for the most-general template? > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/concepts-var-templ1.C: New test. > * g++.dg/cpp2a/concepts-var-templ1a.C: New test. > * g++.dg/cpp2a/concepts-var-templ1b.C: New test. > --- > gcc/cp/decl.c | 11 +++++++++++ > gcc/cp/pt.c | 8 +++++++- > gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C | 9 +++++++++ > gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C | 14 ++++++++++++++ > gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C | 15 +++++++++++++++ > 5 files changed, 56 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C > > diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c > index c0f1496636f..7beac79ec25 100644 > --- a/gcc/cp/decl.c > +++ b/gcc/cp/decl.c > @@ -13980,6 +13980,17 @@ grokdeclarator (const cp_declarator *declarator, > if (declspecs->gnu_thread_keyword_p) > SET_DECL_GNU_TLS_P (decl); > } > + > + /* Set the constraints on declaration. */ > + bool memtmpl = (processing_template_decl > + > template_class_depth (current_class_type)); > + if (memtmpl) > + { > + tree tmpl_reqs > + = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); > + tree ci = build_constraints (tmpl_reqs, NULL_TREE); > + set_constraints (decl, ci); > + } > } > else > { > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index 224dd9ebd2b..613d87f2637 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -2218,7 +2218,8 @@ determine_specialization (tree template_id, > targs = coerce_template_parms (parms, explicit_targs, fns, > tf_warning_or_error, > /*req_all*/true, /*use_defarg*/true); > - if (targs != error_mark_node) > + if (targs != error_mark_node > + && constraints_satisfied_p (fns, targs)) > templates = tree_cons (targs, fns, templates); > } > else for (lkp_iterator iter (fns); iter; ++iter) > @@ -14920,6 +14921,11 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) > if (DECL_NAMESPACE_SCOPE_P (t)) > DECL_NOT_REALLY_EXTERN (r) = 1; > > + /* Propagate the declaration's constraints. */ > + if (VAR_P (r) && DECL_CLASS_SCOPE_P (r)) > + if (tree ci = get_constraints (t)) > + set_constraints (r, ci); > + > DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec); > SET_DECL_IMPLICIT_INSTANTIATION (r); > if (!error_operand_p (r) || (complain & tf_error)) > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C > new file mode 100644 > index 00000000000..80b48ba3a3d > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C > @@ -0,0 +1,9 @@ > +// PR c++/98486 > +// { dg-do compile { target c++20 } } > + > +template<class T, class U> concept C = __is_same(T, U); > + > +template<C<int>> int v; > + > +template<> int v<int>; > +template<> int v<char>; // { dg-error "match" } > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C > new file mode 100644 > index 00000000000..b12d37d8b7e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C > @@ -0,0 +1,14 @@ > +// PR c++/98486 > +// { dg-do compile { target c++20 } } > + > +template<class T, class U> concept C = __is_same(T, U); > + > +struct A { > + template<C<int>> static int v; > +}; > + > +template<> int A::v<int>; > +template<> int A::v<char>; // { dg-error "match" } > + > +int x = A::v<int>; > +int y = A::v<char>; // { dg-error "invalid" } > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C > new file mode 100644 > index 00000000000..37d7f0fc654 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C > @@ -0,0 +1,15 @@ > +// PR c++/98486 > +// { dg-do compile { target c++20 } } > + > +template<class T, class U> concept C = __is_same(T, U); > + > +template<class T> > +struct A { > + template<C<T>> static int v; > +}; > + > +template<> template<> int A<int>::v<int>; > +template<> template<> int A<int>::v<char>; // { dg-error "match" } > + > +int x = A<int>::v<int>; > +int y = A<int>::v<char>; // { dg-error "invalid" } >
On Thu, 16 Sep 2021, Jason Merrill wrote: > On 9/16/21 09:11, Patrick Palka wrote: > > This fixes some issues with constrained variable templates: > > > > * Constraints aren't checked when explicitly specializing a variable > > template > > * Constraints aren't attached to a static data member template at > > parse time > > * Constraints aren't propagated when (partially) instantiating a > > static data member template > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested on > > cmcstl2 and range-v3, does this look OK for trunk and perhaps 11? > > > > PR c++/98486 > > > > gcc/cp/ChangeLog: > > > > * decl.c (grokdeclarator): Set constraints on a static data > > member template. > > * pt.c (determine_specialization): Check constraints on a > > variable template. > > These hunks are OK. > > > (tsubst_decl) <case VAR_DECL>: Propagate constraints on a > > static data member template. > > Hmm, why is this necessary? I know we already do this for functions, but I > don't remember why. Don't we check satisfaction for the most-general > template? Ah true, it looks like propagating constraints is not strictly necessary for satisfaction for that reason.. But propagating them seems necessary for disambiguating constrained overloads in a class template specialization: template<class T> struct A { void f() requires true; // #1 void f() requires false; // #2 }; template struct A<int>; Without the propagation in tsubst_function_decl, during instantiation of A<int> we complain from add_method that #2 cannot be overloaded with #1. But I don't think this is a probem for static data member templates since they can't be overloaded, so indeed there's no reason to propagate constraints on them if we tweak get_normalized_constraints_from_decl. How does the following look? Passes all the concepts tests so far, full testing in progress: -- >8 -- gcc/cp/ChangeLog: * constraint.cc (get_normalized_constraints_from_decl): Look up constraints using the most general template instead of the specialization. * decl.c (grokdeclarator): Set constraints on a static data member template. * pt.c (determine_specialization): Check constraints on a variable template. (tsubst_decl) <case VAR_DECL>: Propagate constraints on a static data member template. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-var-templ1.C: New test. * g++.dg/cpp2a/concepts-var-templ1a.C: New test. * g++.dg/cpp2a/concepts-var-templ1b.C: New test. --- gcc/cp/constraint.cc | 8 +++++--- gcc/cp/decl.c | 11 +++++++++++ gcc/cp/pt.c | 3 ++- gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C | 9 +++++++++ gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C | 14 ++++++++++++++ gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C | 15 +++++++++++++++ 6 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 1aaf1e27886..2896efdd7f2 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -918,20 +918,22 @@ get_normalized_constraints_from_decl (tree d, bool diag = false) tmpl = most_general_template (tmpl); } + d = tmpl ? tmpl : decl; + /* If we're not diagnosing errors, use cached constraints, if any. */ if (!diag) - if (tree *p = hash_map_safe_get (normalized_map, tmpl)) + if (tree *p = hash_map_safe_get (normalized_map, d)) return *p; tree norm = NULL_TREE; - if (tree ci = get_constraints (decl)) + if (tree ci = get_constraints (d)) { push_access_scope_guard pas (decl); norm = get_normalized_constraints_from_info (ci, tmpl, diag); } if (!diag) - hash_map_safe_put<hm_ggc> (normalized_map, tmpl, norm); + hash_map_safe_put<hm_ggc> (normalized_map, d, norm); return norm; } diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c0f1496636f..7beac79ec25 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13980,6 +13980,17 @@ grokdeclarator (const cp_declarator *declarator, if (declspecs->gnu_thread_keyword_p) SET_DECL_GNU_TLS_P (decl); } + + /* Set the constraints on declaration. */ + bool memtmpl = (processing_template_decl + > template_class_depth (current_class_type)); + if (memtmpl) + { + tree tmpl_reqs + = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + tree ci = build_constraints (tmpl_reqs, NULL_TREE); + set_constraints (decl, ci); + } } else { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 224dd9ebd2b..22c74da7935 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2218,7 +2218,8 @@ determine_specialization (tree template_id, targs = coerce_template_parms (parms, explicit_targs, fns, tf_warning_or_error, /*req_all*/true, /*use_defarg*/true); - if (targs != error_mark_node) + if (targs != error_mark_node + && constraints_satisfied_p (fns, targs)) templates = tree_cons (targs, fns, templates); } else for (lkp_iterator iter (fns); iter; ++iter) diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C new file mode 100644 index 00000000000..80b48ba3a3d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C @@ -0,0 +1,9 @@ +// PR c++/98486 +// { dg-do compile { target c++20 } } + +template<class T, class U> concept C = __is_same(T, U); + +template<C<int>> int v; + +template<> int v<int>; +template<> int v<char>; // { dg-error "match" } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C new file mode 100644 index 00000000000..b12d37d8b7e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C @@ -0,0 +1,14 @@ +// PR c++/98486 +// { dg-do compile { target c++20 } } + +template<class T, class U> concept C = __is_same(T, U); + +struct A { + template<C<int>> static int v; +}; + +template<> int A::v<int>; +template<> int A::v<char>; // { dg-error "match" } + +int x = A::v<int>; +int y = A::v<char>; // { dg-error "invalid" } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C new file mode 100644 index 00000000000..37d7f0fc654 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C @@ -0,0 +1,15 @@ +// PR c++/98486 +// { dg-do compile { target c++20 } } + +template<class T, class U> concept C = __is_same(T, U); + +template<class T> +struct A { + template<C<T>> static int v; +}; + +template<> template<> int A<int>::v<int>; +template<> template<> int A<int>::v<char>; // { dg-error "match" } + +int x = A<int>::v<int>; +int y = A<int>::v<char>; // { dg-error "invalid" }
On 9/16/21 12:44, Patrick Palka wrote: > On Thu, 16 Sep 2021, Jason Merrill wrote: > >> On 9/16/21 09:11, Patrick Palka wrote: >>> This fixes some issues with constrained variable templates: >>> >>> * Constraints aren't checked when explicitly specializing a variable >>> template >>> * Constraints aren't attached to a static data member template at >>> parse time >>> * Constraints aren't propagated when (partially) instantiating a >>> static data member template >>> >>> Bootstrapped and regtested on x86_64-pc-linux-gnu, and also tested on >>> cmcstl2 and range-v3, does this look OK for trunk and perhaps 11? >>> >>> PR c++/98486 >>> >>> gcc/cp/ChangeLog: >>> >>> * decl.c (grokdeclarator): Set constraints on a static data >>> member template. >>> * pt.c (determine_specialization): Check constraints on a >>> variable template. >> >> These hunks are OK. >> >>> (tsubst_decl) <case VAR_DECL>: Propagate constraints on a >>> static data member template. >> >> Hmm, why is this necessary? I know we already do this for functions, but I >> don't remember why. Don't we check satisfaction for the most-general >> template? > > Ah true, it looks like propagating constraints is not strictly necessary > for satisfaction for that reason.. > > But propagating them seems necessary for disambiguating constrained > overloads in a class template specialization: > > template<class T> > struct A > { > void f() requires true; // #1 > void f() requires false; // #2 > }; > > template struct A<int>; > > Without the propagation in tsubst_function_decl, during instantiation of > A<int> we complain from add_method that #2 cannot be overloaded with #1. > > But I don't think this is a probem for static data member templates > since they can't be overloaded, so indeed there's no reason to propagate > constraints on them if we tweak get_normalized_constraints_from_decl. > > How does the following look? Passes all the concepts tests so far, full > testing in progress: OK. > -- >8 -- > > gcc/cp/ChangeLog: > > * constraint.cc (get_normalized_constraints_from_decl): Look up > constraints using the most general template instead of the > specialization. > * decl.c (grokdeclarator): Set constraints on a static data > member template. > * pt.c (determine_specialization): Check constraints on a > variable template. > (tsubst_decl) <case VAR_DECL>: Propagate constraints on a > static data member template. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/concepts-var-templ1.C: New test. > * g++.dg/cpp2a/concepts-var-templ1a.C: New test. > * g++.dg/cpp2a/concepts-var-templ1b.C: New test. > --- > gcc/cp/constraint.cc | 8 +++++--- > gcc/cp/decl.c | 11 +++++++++++ > gcc/cp/pt.c | 3 ++- > gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C | 9 +++++++++ > gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C | 14 ++++++++++++++ > gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C | 15 +++++++++++++++ > 6 files changed, 56 insertions(+), 4 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc > index 1aaf1e27886..2896efdd7f2 100644 > --- a/gcc/cp/constraint.cc > +++ b/gcc/cp/constraint.cc > @@ -918,20 +918,22 @@ get_normalized_constraints_from_decl (tree d, bool diag = false) > tmpl = most_general_template (tmpl); > } > > + d = tmpl ? tmpl : decl; > + > /* If we're not diagnosing errors, use cached constraints, if any. */ > if (!diag) > - if (tree *p = hash_map_safe_get (normalized_map, tmpl)) > + if (tree *p = hash_map_safe_get (normalized_map, d)) > return *p; > > tree norm = NULL_TREE; > - if (tree ci = get_constraints (decl)) > + if (tree ci = get_constraints (d)) > { > push_access_scope_guard pas (decl); > norm = get_normalized_constraints_from_info (ci, tmpl, diag); > } > > if (!diag) > - hash_map_safe_put<hm_ggc> (normalized_map, tmpl, norm); > + hash_map_safe_put<hm_ggc> (normalized_map, d, norm); > > return norm; > } > diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c > index c0f1496636f..7beac79ec25 100644 > --- a/gcc/cp/decl.c > +++ b/gcc/cp/decl.c > @@ -13980,6 +13980,17 @@ grokdeclarator (const cp_declarator *declarator, > if (declspecs->gnu_thread_keyword_p) > SET_DECL_GNU_TLS_P (decl); > } > + > + /* Set the constraints on declaration. */ > + bool memtmpl = (processing_template_decl > + > template_class_depth (current_class_type)); > + if (memtmpl) > + { > + tree tmpl_reqs > + = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); > + tree ci = build_constraints (tmpl_reqs, NULL_TREE); > + set_constraints (decl, ci); > + } > } > else > { > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index 224dd9ebd2b..22c74da7935 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -2218,7 +2218,8 @@ determine_specialization (tree template_id, > targs = coerce_template_parms (parms, explicit_targs, fns, > tf_warning_or_error, > /*req_all*/true, /*use_defarg*/true); > - if (targs != error_mark_node) > + if (targs != error_mark_node > + && constraints_satisfied_p (fns, targs)) > templates = tree_cons (targs, fns, templates); > } > else for (lkp_iterator iter (fns); iter; ++iter) > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C > new file mode 100644 > index 00000000000..80b48ba3a3d > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C > @@ -0,0 +1,9 @@ > +// PR c++/98486 > +// { dg-do compile { target c++20 } } > + > +template<class T, class U> concept C = __is_same(T, U); > + > +template<C<int>> int v; > + > +template<> int v<int>; > +template<> int v<char>; // { dg-error "match" } > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C > new file mode 100644 > index 00000000000..b12d37d8b7e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C > @@ -0,0 +1,14 @@ > +// PR c++/98486 > +// { dg-do compile { target c++20 } } > + > +template<class T, class U> concept C = __is_same(T, U); > + > +struct A { > + template<C<int>> static int v; > +}; > + > +template<> int A::v<int>; > +template<> int A::v<char>; // { dg-error "match" } > + > +int x = A::v<int>; > +int y = A::v<char>; // { dg-error "invalid" } > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C > new file mode 100644 > index 00000000000..37d7f0fc654 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C > @@ -0,0 +1,15 @@ > +// PR c++/98486 > +// { dg-do compile { target c++20 } } > + > +template<class T, class U> concept C = __is_same(T, U); > + > +template<class T> > +struct A { > + template<C<T>> static int v; > +}; > + > +template<> template<> int A<int>::v<int>; > +template<> template<> int A<int>::v<char>; // { dg-error "match" } > + > +int x = A<int>::v<int>; > +int y = A<int>::v<char>; // { dg-error "invalid" } >
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c0f1496636f..7beac79ec25 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13980,6 +13980,17 @@ grokdeclarator (const cp_declarator *declarator, if (declspecs->gnu_thread_keyword_p) SET_DECL_GNU_TLS_P (decl); } + + /* Set the constraints on declaration. */ + bool memtmpl = (processing_template_decl + > template_class_depth (current_class_type)); + if (memtmpl) + { + tree tmpl_reqs + = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + tree ci = build_constraints (tmpl_reqs, NULL_TREE); + set_constraints (decl, ci); + } } else { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 224dd9ebd2b..613d87f2637 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2218,7 +2218,8 @@ determine_specialization (tree template_id, targs = coerce_template_parms (parms, explicit_targs, fns, tf_warning_or_error, /*req_all*/true, /*use_defarg*/true); - if (targs != error_mark_node) + if (targs != error_mark_node + && constraints_satisfied_p (fns, targs)) templates = tree_cons (targs, fns, templates); } else for (lkp_iterator iter (fns); iter; ++iter) @@ -14920,6 +14921,11 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (DECL_NAMESPACE_SCOPE_P (t)) DECL_NOT_REALLY_EXTERN (r) = 1; + /* Propagate the declaration's constraints. */ + if (VAR_P (r) && DECL_CLASS_SCOPE_P (r)) + if (tree ci = get_constraints (t)) + set_constraints (r, ci); + DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec); SET_DECL_IMPLICIT_INSTANTIATION (r); if (!error_operand_p (r) || (complain & tf_error)) diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C new file mode 100644 index 00000000000..80b48ba3a3d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1.C @@ -0,0 +1,9 @@ +// PR c++/98486 +// { dg-do compile { target c++20 } } + +template<class T, class U> concept C = __is_same(T, U); + +template<C<int>> int v; + +template<> int v<int>; +template<> int v<char>; // { dg-error "match" } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C new file mode 100644 index 00000000000..b12d37d8b7e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1a.C @@ -0,0 +1,14 @@ +// PR c++/98486 +// { dg-do compile { target c++20 } } + +template<class T, class U> concept C = __is_same(T, U); + +struct A { + template<C<int>> static int v; +}; + +template<> int A::v<int>; +template<> int A::v<char>; // { dg-error "match" } + +int x = A::v<int>; +int y = A::v<char>; // { dg-error "invalid" } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C new file mode 100644 index 00000000000..37d7f0fc654 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-var-templ1b.C @@ -0,0 +1,15 @@ +// PR c++/98486 +// { dg-do compile { target c++20 } } + +template<class T, class U> concept C = __is_same(T, U); + +template<class T> +struct A { + template<C<T>> static int v; +}; + +template<> template<> int A<int>::v<int>; +template<> template<> int A<int>::v<char>; // { dg-error "match" } + +int x = A<int>::v<int>; +int y = A<int>::v<char>; // { dg-error "invalid" }