aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2024-09-18 13:50:43 -0400
committerPatrick Palka <ppalka@redhat.com>2024-09-18 13:50:43 -0400
commit82c2acd0bc4411524a8248fcdce219927d921a71 (patch)
tree934e416ed00fbdabacd2766bc3001d02379b4b36 /gcc
parentfe1ed68000d5e9d41ed48ef1202fd21c8b8c9ff8 (diff)
downloadgcc-82c2acd0bc4411524a8248fcdce219927d921a71.zip
gcc-82c2acd0bc4411524a8248fcdce219927d921a71.tar.gz
gcc-82c2acd0bc4411524a8248fcdce219927d921a71.tar.bz2
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 <jason@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/pt.cc11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/lambda-uneval18.C39
2 files changed, 48 insertions, 2 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 769e799..e826206 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 0000000..b7d864c
--- /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>();