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>();

Reply via email to