]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: alias of decltype(lambda) is opaque [PR116714, PR107390]
authorPatrick Palka <ppalka@redhat.com>
Wed, 18 Sep 2024 17:50:43 +0000 (13:50 -0400)
committerPatrick Palka <ppalka@redhat.com>
Wed, 18 Sep 2024 17:50:43 +0000 (13:50 -0400)
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>
gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp2a/lambda-uneval18.C [new file with mode: 0644]

index 769e7999dac1132d0f382c493a42b3d0d75023f7..e826206be1644991b790a8dada244022880a818a 100644 (file)
@@ -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 (file)
index 0000000..b7d864c
--- /dev/null
@@ -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>();