https://gcc.gnu.org/g:82c2acd0bc4411524a8248fcdce219927d921a71
commit r15-3694-g82c2acd0bc4411524a8248fcdce219927d921a71 Author: Patrick Palka <ppa...@redhat.com> Date: Wed Sep 18 13:50:43 2024 -0400 c++: alias of decltype(lambda) is opaque [PR116714, PR107390] Here for using type = decltype([]{}); static_assert(is_same_v<type, type>); we strip the alias ahead of time during template argument coercion which effectively transforms the template-id into is_same_v<decltype([]{}), decltype([]{})> which is wrong because later substitution into the template-id will produce two new lambdas with distinct types and cause is_same_v to return false. This demonstrates that such aliases should be considered opaque (a notion that we recently introduced in r15-2331-g523836716137d0). (An alternative solution might be to consider memoizing lambda-expr substitution rather than always producing a new lambda, but this is much simpler.) PR c++/116714 PR c++/107390 gcc/cp/ChangeLog: * pt.cc (dependent_opaque_alias_p): Also return true for a decltype(lambda) alias. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-uneval18.C: New test. Reviewed-by: Jason Merrill <ja...@redhat.com> Diff: --- gcc/cp/pt.cc | 11 ++++++-- gcc/testsuite/g++.dg/cpp2a/lambda-uneval18.C | 39 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 769e7999dac1..e826206be164 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -6759,8 +6759,15 @@ dependent_opaque_alias_p (const_tree t) { return (TYPE_P (t) && typedef_variant_p (t) - && any_dependent_type_attributes_p (DECL_ATTRIBUTES - (TYPE_NAME (t)))); + && (any_dependent_type_attributes_p (DECL_ATTRIBUTES + (TYPE_NAME (t))) + /* Treat a dependent decltype(lambda) alias as opaque so that we + don't prematurely strip it when used as a template argument. + Otherwise substitution into each occurrence of the (stripped) + alias would incorrectly yield a distinct lambda type. */ + || (TREE_CODE (t) == DECLTYPE_TYPE + && TREE_CODE (DECLTYPE_TYPE_EXPR (t)) == LAMBDA_EXPR + && !typedef_variant_p (DECL_ORIGINAL_TYPE (TYPE_NAME (t)))))); } /* Return the number of innermost template parameters in TMPL. */ diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval18.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval18.C new file mode 100644 index 000000000000..b7d864c62453 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval18.C @@ -0,0 +1,39 @@ +// PR c++/116714 +// PR c++/107390 +// { dg-do compile { target c++20 } } + +template<class T, class U> +inline constexpr bool is_same_v = __is_same(T, U); + +template<class T, class U> +struct is_same { static constexpr bool value = false; }; + +template<class T> +struct is_same<T, T> { static constexpr bool value = true; }; + +template<class> +void f() { + using type = decltype([]{}); + static_assert(is_same_v<type, type>); + static_assert(is_same<type, type>::value); +}; + +template<class> +void g() { + using ty1 = decltype([]{}); + using ty2 = ty1; + static_assert(is_same_v<ty1, ty2>); + static_assert(is_same<ty1, ty2>::value); +}; + +template<class> +void h() { + using ty1 = decltype([]{}); + using ty2 = decltype([]{}); + static_assert(!is_same_v<ty1, ty2>); + static_assert(!is_same<ty1, ty2>::value); +}; + +template void f<int>(); +template void g<int>(); +template void h<int>();