Message ID | 20200601164718.1522132-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: constrained lambda inside template [PR92633] | expand |
On 6/1/20 12:47 PM, Patrick Palka wrote: > When regenerating a constrained lambda during instantiation of an > enclosing template, we are forgetting to substitute into the lambda's > constraints. Fix this by substituting through the constraints during > tsubst_lambda_expr. > > Passes 'make check-c++', and also tested by building the testsuites of > cmcstl2 and range-v3. Does this look OK to commit to master and to the > 10 branch after a full bootstrap and regtest? OK for both. > gcc/cp/ChangeLog: > > PR c++/92633 > PR c++/92838 > * pt.c (tsubst_function_decl): Don't do set_constraints when > regenerating a lambda. > (tsubst_lambda_expr): Substitute into the lambda's constraints > and do set_constraints here. > > gcc/testsuite/ChangeLog: > > PR c++/92633 > PR c++/92838 > * g++.dg/cpp2a/concepts-lambda11.C: New test. > * g++.dg/cpp2a/concepts-lambda12.C: New test. > --- > gcc/cp/pt.c | 16 +++++++++++++++- > gcc/testsuite/g++.dg/cpp2a/concepts-lambda11.C | 17 +++++++++++++++++ > gcc/testsuite/g++.dg/cpp2a/concepts-lambda12.C | 15 +++++++++++++++ > 3 files changed, 47 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda11.C > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda12.C > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index df647af7b46..907ca879c73 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -13854,7 +13854,10 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, > don't substitute through the constraints; that's only done when > they are checked. */ > if (tree ci = get_constraints (t)) > - set_constraints (r, ci); > + /* Unless we're regenerating a lambda, in which case we'll set the > + lambda's constraints in tsubst_lambda_expr. */ > + if (!lambda_fntype) > + set_constraints (r, ci); > > if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t)) > SET_DECL_FRIEND_CONTEXT (r, > @@ -19029,6 +19032,17 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) > finish_member_declaration (fn); > } > > + if (tree ci = get_constraints (oldfn)) > + { > + /* Substitute into the lambda's constraints. */ > + if (oldtmpl) > + ++processing_template_decl; > + ci = tsubst_constraint_info (ci, args, complain, in_decl); > + if (oldtmpl) > + --processing_template_decl; > + set_constraints (fn, ci); > + } > + > /* Let finish_function set this. */ > DECL_DECLARED_CONSTEXPR_P (fn) = false; > > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda11.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda11.C > new file mode 100644 > index 00000000000..dd9cd4e2344 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda11.C > @@ -0,0 +1,17 @@ > +// PR c++/92838 > +// { dg-do compile { target c++20 } } > + > +template<int N> > +auto foo() > +{ > + [] () requires (N != 0) { }(); // { dg-error "no match" } > + [] () requires (N == 0) { }(); > + > + [] <int M=1> () requires (N == M) { }(); // { dg-error "no match" } > + [] <int M=1> () requires (N != M) { }(); > +} > + > +void bar() > +{ > + foo<0>(); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda12.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda12.C > new file mode 100644 > index 00000000000..2bc9fd0bb25 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda12.C > @@ -0,0 +1,15 @@ > +// PR c++/92633 > +// { dg-do compile { target c++20 } } > + > +template<class A, class B> > +concept different_than = !__is_same_as(A, B); > + > +template<class B> > +auto diff(B) { > + return [](different_than<B> auto a) {}; > +} > + > +int main() { > + diff(42)(""); > + diff(42)(42); // { dg-error "no match" } > +} >
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index df647af7b46..907ca879c73 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13854,7 +13854,10 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, don't substitute through the constraints; that's only done when they are checked. */ if (tree ci = get_constraints (t)) - set_constraints (r, ci); + /* Unless we're regenerating a lambda, in which case we'll set the + lambda's constraints in tsubst_lambda_expr. */ + if (!lambda_fntype) + set_constraints (r, ci); if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t)) SET_DECL_FRIEND_CONTEXT (r, @@ -19029,6 +19032,17 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) finish_member_declaration (fn); } + if (tree ci = get_constraints (oldfn)) + { + /* Substitute into the lambda's constraints. */ + if (oldtmpl) + ++processing_template_decl; + ci = tsubst_constraint_info (ci, args, complain, in_decl); + if (oldtmpl) + --processing_template_decl; + set_constraints (fn, ci); + } + /* Let finish_function set this. */ DECL_DECLARED_CONSTEXPR_P (fn) = false; diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda11.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda11.C new file mode 100644 index 00000000000..dd9cd4e2344 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda11.C @@ -0,0 +1,17 @@ +// PR c++/92838 +// { dg-do compile { target c++20 } } + +template<int N> +auto foo() +{ + [] () requires (N != 0) { }(); // { dg-error "no match" } + [] () requires (N == 0) { }(); + + [] <int M=1> () requires (N == M) { }(); // { dg-error "no match" } + [] <int M=1> () requires (N != M) { }(); +} + +void bar() +{ + foo<0>(); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda12.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda12.C new file mode 100644 index 00000000000..2bc9fd0bb25 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda12.C @@ -0,0 +1,15 @@ +// PR c++/92633 +// { dg-do compile { target c++20 } } + +template<class A, class B> +concept different_than = !__is_same_as(A, B); + +template<class B> +auto diff(B) { + return [](different_than<B> auto a) {}; +} + +int main() { + diff(42)(""); + diff(42)(42); // { dg-error "no match" } +}